android wear development

77
Android Wear Development Johnny Sung 2015.01.28 @ Android Taipei Friday, January 30, 15

Upload: johnny-sung

Post on 15-Jul-2015

2.223 views

Category:

Technology


1 download

TRANSCRIPT

Android Wear DevelopmentJohnny Sung

2015.01.28 @ Android TaipeiFriday, January 30, 15

https://fb.com/j796160836

Johnny SungMobile devices Developer

https://plus.google.com/+JohnnySung

http://about.me/j796160836

Friday, January 30, 15

Agenda• Overview

• Basic Setup

• Notifications

• Layout

• Data Layer

• Comparison with WatchKit

Friday, January 30, 15

http://www.droid-life.com/wp-content/uploads/2014/03/android-wear.png

https://www.youtube.com/watch?v=CZrGDo9Grgk (30sec)https://www.youtube.com/watch?v=QrqZl2QIz0c (1.5min)

TVCF

Friday, January 30, 15

http://img1.lesnumeriques.com/news/33/33684/gg-android-wear-tag.jpg

Friday, January 30, 15

Android Wear 設計理念

• Launched automatically (⾃自動啟動)

• Glanceable (可⼀一眼瞥⾒見)

• All about suggest and demand (推薦與需求)

• Zero or low interaction (盡可能減少點擊滑動步驟)

Friday, January 30, 15

http://core0.staticworld.net/images/article/2014/06/android_wear_sports_score-100314393-orig.jpg

Friday, January 30, 15

http://i2.tudocdn.net/img/type28/width646/height284/id106674.jpg

Friday, January 30, 15

Basic setup

Friday, January 30, 15

Debugging over Bluetooth

• ⼿手機設定 Debugging over bluetooth

• ⼿手錶設定 ADB Debug & Debugging over bluetooth

• 執⾏行 ConnectDebugWear.shhttps://gist.github.com/j796160836/9b135a8de4c44846fd82

Friday, January 30, 15

Debugging over Bluetooth

Friday, January 30, 15

https://www.youtube.com/watch?v=q3a2fdTy_6A

Connect use USB?

Friday, January 30, 15

Android Wear Emulator & Phone Emulator

Friday, January 30, 15

Android Wear Emulator & Phone Emulator

• Choose x86 Emulator (faster)

• Install Google Search (2min)com.google.android.googlequicksearchbox-3.6.16.1614640.x86.apk

• Install Android Wear (2min)com.google.android.wearable.app

• Be patient

Friday, January 30, 15

Friday, January 30, 15

WearHost for Genymotion• Install ARM Translation Installer

Genymotion-ARM-Translation_v1.1.zip

• Install GAppsgapps-lp-20141109-signed.zipgapps-kk-20140606-signed.zipgapps-jb-20130813-signed.zip

• Install Google Searchcom.google.android.googlequicksearchbox

• Install Android Wearcom.google.android.wearable.app

• Run Script: ConnectWearEmulator.shhttps://gist.github.com/j796160836/91e77ca819c11ed7bf01

Friday, January 30, 15

Eclipse user?

Friday, January 30, 15

Compile Wear in Eclipse• Install Google Repository in SDK Manager

• Find wearable-1.1.0.aar in SDKandroid-sdks/extras/google/m2repository/com/google/android/support/wearable/1.0.0/wearable-1.1.0.aar

• Rename aar to zip and unzip it

• Import from existing code

• Check it Is Library

• Import google-play-service-libhttps://medium.com/@tangtungai/ef1b34126a5d

Friday, January 30, 15

Compile Wear in Android Studio

• Edit Gradle

dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.google.android.support:wearable:1.1.0' compile 'com.google.android.gms:play-services-wearable:6.5.87'}

[Wearable module]

Friday, January 30, 15

Packaging structure

Android App

Android App

Code

Resources

Code

ResourcesWear App

WearApp Module HandledApp Module

Friday, January 30, 15

Packaging Wearables using Ant

1. Export and Sign Wearable Apps APK(eg: demowearapp.apk)

2. Add a meta-data tag in AndroidManifest.xml

3. Put your wearable binary in res/raw directory(eg: res/raw/demowearapp.apk)

4. Write reference descriptions xml(eg: res/xml/wearable_app_desc.xml)

5. Turn off Asset Compressionhttps://developer.android.com/training/wearables/apps/packaging.html#PackageManuallyhttps://medium.com/@tangtungai/ef1b34126a5d

Friday, January 30, 15

Packaging Wearables in Eclipse

1. Export and Sign Wearable Apps APK(eg: demowearapp.apk)

#!/bin/bash

cd ../wearable-1.1.0android update lib-project --path .ant clean release

cd ../DemoWearAppandroid update project --path .ant clean release

key.store=TEST.keystorekey.store.password=PASSWORDkey.alias=KEYSTORE_ALIASkey.alias.password=PASSWORDconfig.logging=true

ant.properties

Generate build.xml

[Wearable project]

Friday, January 30, 15

Packaging Wearables in Eclipse

2. Add a meta-data tag in AndroidManifest.xml

<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- ... -->

<meta-data android:name="com.google.android.wearable.beta.app" android:resource="@xml/wearable_app_desc" /></application>

[Smartphone project]

Friday, January 30, 15

Packaging Wearables in Eclipse

3. Put your wearable binary in res/raw directory(eg: res/raw/demowearapp.apk)

4. Write reference descriptions xml(eg: res/xml/wearable_app_desc.xml)

<?xml version="1.0" encoding="utf-8"?><wearableApp package="com.example.demowearapp"> <versionCode>1</versionCode> <versionName>1.0</versionName> <rawPathResId>demowearapp</rawPathResId> </wearableApp>

[Smartphone project]

Friday, January 30, 15

Packaging Wearables in Eclipse5. Turn off Asset Compression

<target name="-package-resources" depends="-crunch"> <do-only-if-not-library elseText="Library project: do not package resources..." > <aapt executable="${aapt}" command="package" versioncode="${version.code}" versionname="${version.name}" debug="${build.is.packaging.debug}" manifest="${out.manifest.abs.file}" assets="${asset.absolute.dir}" androidjar="${project.target.android.jar}" apkfolder="${out.absolute.dir}" nocrunch="${build.packaging.nocrunch}" resourcefilename="${resource.package.file.name}" resourcefilter="${aapt.resource.filter}" libraryResFolderPathRefid="project.library.res.folder.path" libraryPackagesRefid="project.library.packages" libraryRFileRefid="project.library.bin.r.file.path" previousBuildType="${build.last.target}" buildType="${build.target}" ignoreAssets="${aapt.ignore.assets}"> <res path="${out.res.absolute.dir}" /> <res path="${resource.absolute.dir}" />

<nocompress extension="apk" /> </aapt> </do-only-if-not-library></target>

http://stackoverflow.com/questions/7937368/how-to-pass-arguments-to-aapt-when-building-android-apk

From <sdks_dir>/tools/ant/build.xml, search -package-resources

Add this

[Smartphone project]

Friday, January 30, 15

[Smartphone module]dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.google.android.gms:play-services:6.5.87' wearApp project(':wear')}

Packaging Wearables in Android Studio

• Edit Gradle

Friday, January 30, 15

Code Examples

AndroidWearable-Sampleshttp://goo.gl/q8qfm8

DemoWearApphttp://goo.gl/pIJzr4

Friday, January 30, 15

Notifications

Friday, January 30, 15

世新廣播電Personal Works

Friday, January 30, 15

Shih Hsin Radio Station

• Actions• WearableExtender

• Background• Page

Friday, January 30, 15

Notification 整理• Notification 到底要怎麼發?

• 從⼿手機發送

• 同步到⼿手錶(含變更樣式)

• 不同步到⼿手錶

• 從⼿手錶發送

mBuilder.setLocalOnly(true);

Friday, January 30, 15

Notification 整理• Notification 變更樣式?

• 從⼿手機發送

• 設定⼿手機樣式,再變更⼿手錶樣式

• ⾃自訂樣式(只適⽤用於⼿手機)

• 從⼿手錶發送

• ⾃自訂樣式(只適⽤用於⼿手錶)

WearableExtender

WearableExtendersetDisplayIntent

RemoteView

Friday, January 30, 15

基本款 Notification

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.ic_launcher);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText("The description");Notification notification = mBuilder.build();

int NOTIFICATION_ID = 0x01;

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);mNotificationManager.notify(NOTIFICATION_ID, notification);

建⽴立

發送

Friday, January 30, 15

Notification notification = new Notification(R.drawable.ic_launcher, "New Notification!", System.currentTimeMillis());notification.setLatestEventInfo(this , "Awesome app" , "The description", pending);

基本款 Notification

舊寫法 (deprecated  in  API  level  11)

拜託別再寫了哈~Friday, January 30, 15

基本款 Notification

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.ic_launcher);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText("The description");Notification notification = mBuilder.build();

Friday, January 30, 15

Android  4.1  (API  16)BigTextStyle

String msg = "\"The quick brown fox …";NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.ic_launcher);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText(msg);mBuilder.setStyle( new NotificationCompat.BigTextStyle() .bigText(msg));Notification notification = mBuilder.build();

http://developer.android.com/training/notify-user/expanded.htmlFriday, January 30, 15

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.photo);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText("The description");

Bitmap bg = BitmapFactory.decodeResource( getResources(), R.drawable.bg);

NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();style.bigPicture(bg);style.setBigContentTitle("My title");style.setSummaryText("The description");mBuilder.setStyle(style);

Notification notification = mBuilder.build();

BigPictureStyle Android  4.1  (API  16)

Friday, January 30, 15

Notification Height Limit• Normal view layouts: 64 dp

• Expanded view layouts: 256 dp.

256dp

64dp

Friday, January 30, 15

WearableExtender

Friday, January 30, 15

基本款 Notification + 背景

• Background size• 400 x 400• 640 x 400 (Parallax scrolling)

• Put the picture at /res/drawable-nodpi

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.photo);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText("The description");

Bitmap bg = BitmapFactory.decodeResource( getResources(), R.drawable.bg);

NotificationCompat.WearableExtender wearExt = new NotificationCompat.WearableExtender() .setBackground(bg);mBuilder.extend(wearExt);

Notification notification = mBuilder.build();

Friday, January 30, 15

RemoteControlClient Android  4.0  (API  14)

METADATA_KEY_ARTIST

Friday, January 30, 15

RemoteControlClient Android  4.0  (API  14)

• Attribute Keys• METADATA_KEY_ARTIST• METADATA_KEY_TITLE

• Attribute Keys• METADATA_KEY_TITLE• METADATA_KEY_ALBUM

RemoteView

Friday, January 30, 15

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.photo);mBuilder.setContentTitle("Awesome app");mBuilder.setContentText("The description");

Intent clickInt = new Intent(MainActivity.this, SecondActivity.class);

PendingIntent clickPenInt = PendingIntent.getActivity(this, 0, clickInt, PendingIntent.FLAG_UPDATE_CURRENT);mBuilder.setContentIntent(clickPenInt);

Notification notification = mBuilder.build();

按鈕按下的⾏行為

Friday, January 30, 15

24dp

48dp

The Problem is…

Friday, January 30, 15

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);mBuilder.setSmallIcon(R.drawable.ic_launcher);mBuilder.setContentTitle("世新廣播電臺");mBuilder.setContentText("⼤大⾃自然守護者...");

mBuilder.addAction(new NotificationCompat.Action (R.drawable.cancel, "Dismiss", dismissPenInt));mBuilder.addAction(new NotificationCompat.Action (R.drawable.listen, "Listen FM", listenPenInt));

NotificationCompat.WearableExtender wExt = new NotificationCompat.WearableExtender();

wExt.addAction(new NotificationCompat.Action (R.drawable.listen_wear, "Listen FM",listenPenInt));

Notification notification = mBuilder.build();

http://stackoverflow.com/questions/25026616/android-wear-action-item-icon-sizing-vs-phone-notification-action-item-sizing

The solutions

Friday, January 30, 15

Code ExamplesWearable Notificationshttps://github.com/googlesamples/android-Notifications

Basic Notificationshttps://github.com/googlesamples/android-BasicNotifications

Custom Notificationshttps://github.com/googlesamples/android-CustomNotifications

Friday, January 30, 15

• WatchViewStub

• 指定 Round layout

• 指定 Rect layout

• BoxInsetLayout

• 設定 app:layout_box="all"

Layout

http://developer.android.com/training/wearables/ui/layouts.htmlFriday, January 30, 15

Layout• Card

• 繼承 CardFragment

• CardScrollView + CardFrame

http://developer.android.com/training/wearables/ui/cards.htmlFriday, January 30, 15

UI Structure

Friday, January 30, 15

Data Layer

Friday, January 30, 15

Google  Play  Services

Friday, January 30, 15

Bluetooth

Mini

Friday, January 30, 15

Data Layer 資料傳輸層

• DataApi

• MessageApi

• NodeApi

Friday, January 30, 15

Data Items

• Path唯⼀一的字符串,必須以正斜線開始例如:/path/to/data

• Payload⼀一個字節數組,你可允許進⾏行對象的序列化 (Serialize) 與反序列化 (Deserialize)⼤大⼩小不能超過100KB。

PathPayload

100KB

Friday, January 30, 15

連接⽅方式• 在 Activity 中建⽴立連線,實作 Callback 監聽

• 使⽤用 WearableListenerService

• Callback

• DataApi.DataListener

• MessageApi.MessageListener

• NodeApi.NodeListener

Friday, January 30, 15

Listener• DataApi.DataListener

• NodeApi.NodeListener

• MessageApi.MessageListener

public void onPeerConnected(Node node)public void onPeerDisconnected(Node node)

public void onDataChanged(DataEventBuffer dataEvents)

public void onMessageReceived(MessageEvent messageEvent)

Friday, January 30, 15

連接⽅方式• onCreate() 建⽴立 GoogleApiClient,掛載 Callbacks

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Wearable.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build();}

Friday, January 30, 15

連線 Callback

public void onConnected(Bundle connectionHint)

public void onConnectionFailed(ConnectionResult result)

• GoogleApiClient.ConnectionCallbacks

• GoogleApiClient.OnConnectionFailedListenerpublic void onConnectionSuspended(int cause)

https://developer.android.com/google/auth/api-client.html

Friday, January 30, 15

連接⽅方式• onStart() 呼叫 connect() 做連線@Overrideprotected void onStart() { super.onStart(); if (!mResolvingError) { mGoogleApiClient.connect(); }}

@Override //ConnectionCallbackspublic void onConnected(Bundle connectionHint) { Log.d(TAG, "Google API Client was connected"); mResolvingError = false; Wearable.DataApi.addListener(mGoogleApiClient, this); Wearable.MessageApi.addListener(mGoogleApiClient, this); Wearable.NodeApi.addListener(mGoogleApiClient, this);}

• onConnected() 時候,掛載 Listener

Friday, January 30, 15

@Overrideprotected void onStop() { if (!mResolvingError) { Wearable.DataApi.removeListener(mGoogleApiClient, this); Wearable.MessageApi.removeListener(mGoogleApiClient, this); Wearable.NodeApi.removeListener(mGoogleApiClient, this); mGoogleApiClient.disconnect(); } super.onStop();}

連接⽅方式• onStop() 移除Listener,並且斷線

Friday, January 30, 15

WearableListenerService• 在系統需要的時候就會⾃自動綁定

<service android:name=".DataLayerListenerService" > <intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> </intent-filter></service>

public class DataLayerListenerService extends WearableListenerService {

@Override public void onDataChanged(DataEventBuffer dataEvents) { // Do Somthing } @Override public void onMessageReceived(MessageEvent messageEvent) { // Do Somthing }}

AndroidManifest.xml

Friday, January 30, 15

DataApi

http://android-wear-docs.readthedocs.org/en/latest/data.htmlFriday, January 30, 15

DataItemprivate void sendSampleDataItem() { final PutDataMapRequest putRequest = PutDataMapRequest.create("/SAMPLE"); final DataMap map = putRequest.getDataMap(); map.putInt("num", 12345); map.putString("example", "Sample String"); Wearable.DataApi.putDataItem(mGoogleApiClient, putRequest.asPutDataRequest());}

@Overridepublic void onDataChanged(DataEventBuffer dataEvents) { final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);

dataEvents.close(); for(DataEvent event : events) { String path = event.getDataItem().getUri().getPath(); if(path.equals("/SAMPLE")) { final DataMap map = DataMapItem.fromDataItem(event.getDataItem()).getDataMap(); // read your values from map: int num = map.getInt("num"); String str = map.getString(“example"); Log.v(TAG, " num = " + num + " str = " + str); } }}

• 傳送

• 接收

Friday, January 30, 15

MessageApi

http://android-wear-docs.readthedocs.org/en/latest/sync.htmlFriday, January 30, 15

String msg = "Sample String";NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi .getConnectedNodes(mGoogleApiClient).await();for (Node node : nodes.getNodes()) { SendMessageResult result = Wearable.MessageApi.sendMessage( mGoogleApiClient, node.getId(), "/SAMPLE", msg.getBytes()) .await(); if (result.getStatus().isSuccess()) { // Success } else { // Error }}

@Overridepublic void onMessageReceived(MessageEvent messageEvent) {

if (messageEvent.getPath().equals("/SAMPLE")) { final String message = new String(messageEvent.getData());

// Do Something }}

• 傳送Message (AsyncTask)

• 接收Message

Message

Friday, January 30, 15

Code Examples

WearMessageBringFronthttp://goo.gl/jdKkHL

WearDataLayerDemohttp://goo.gl/HL84YQ

DataLayerhttps://github.com/googlesamples/android-DataLayer

Friday, January 30, 15

vsApple Watch(WatchKit) Android Wear

Friday, January 30, 15

Android Wear

WatchKit

Packaging structure

Android App

Android App

CodeResources

Code

ResourcesWear App

WearApp Module HandledApp ModuleFriday, January 30, 15

Android Wear

Google Play ServicesGoogle Play Services

Android Device

ControllerModel

View

Mini

Controller

View

Model

Controller

View

Model

App structure

Android Wear

WatchKit

iOS App

Friday, January 30, 15

好像少講了什麼?

Friday, January 30, 15

震動。

超⾃自然的

Friday, January 30, 15

震動<uses-permission android:name="android.permission.VIBRATE" />

Vibrator mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

myVibrator.vibrate(100);

AndroidManifest.xml

Friday, January 30, 15

震動

mVibrator.vibrate(new long[]{80, 150, 80, 150, 80, 150}, -1);

Repeat

Pattern

mVibrator.cancel();

震動 Pattern

取消

Friday, January 30, 15

Q & A

Friday, January 30, 15

Troubleshooting: ⼿手錶 Offline 解決⽅方式

• Android Wear (設定 > 應⽤用程式)

1. 停⽤用

2. 清除資料

3. 啟⽤用

• Google Play 服務 (設定 > 應⽤用程式)

1. 清除所有資料(管理空間)

• 硬體

1. 重置⼿手錶

2. ⼿手機重新啟動

http://melix.github.io/blog/2014/10/android-moto360.html

$ adb devicesList of devices attached

dcfbbafd! devicelocalhost:4444 offline

Friday, January 30, 15

Android Wear(設定 > 應⽤用程式)

Google Play 服務 (設定 > 應⽤用程式 > 管理空間)

重置 Moto360

Troubleshooting: ⼿手錶 Offline 解決⽅方式

Friday, January 30, 15

Troubleshooting: ⼿手錶 unauthorized 解決⽅方式

• 請使⽤用 Eclipse 做第⼀一次連接$ adb devicesList of devices attached

dcfbbafd! devicelocalhost:4444 unauthorized

Friday, January 30, 15