Slide 1

Slide 1 text

Android Wear Development Johnny Sung 2015.01.28 @ Android Taipei

Slide 2

Slide 2 text

https://fb.com/j796160836 Johnny Sung Mobile devices Developer https://plus.google.com/+JohnnySung http://about.me/j796160836

Slide 3

Slide 3 text

Agenda • Overview • Basic Setup • Notifications • Layout • Data Layer • Comparison with WatchKit

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Android Wear 設計理念 • Launched automatically (⾃自動啟動) • Glanceable (可⼀一眼瞥⾒見) • All about suggest and demand (推薦與需求) • Zero or low interaction (盡可能減少點擊滑動步驟)

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Basic setup

Slide 10

Slide 10 text

Debugging over Bluetooth • ⼿手機設定 Debugging over bluetooth • ⼿手錶設定 ADB Debug
 & Debugging over bluetooth • 執⾏行 ConnectDebugWear.sh
 https://gist.github.com/j796160836/9b135a8de4c44846fd82

Slide 11

Slide 11 text

Debugging over Bluetooth

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Android Wear Emulator
 & Phone Emulator

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

WearHost for Genymotion • Install ARM Translation Installer
 Genymotion-ARM-Translation_v1.1.zip • Install GApps
 gapps-lp-20141109-signed.zip
 gapps-kk-20140606-signed.zip
 gapps-jb-20130813-signed.zip • Install Google Search
 com.google.android.googlequicksearchbox • Install Android Wear
 com.google.android.wearable.app • Run Script: ConnectWearEmulator.sh
 https://gist.github.com/j796160836/91e77ca819c11ed7bf01

Slide 17

Slide 17 text

Eclipse user?

Slide 18

Slide 18 text

Compile Wear in Eclipse • Install Google Repository in SDK Manager • Find wearable-1.1.0.aar in SDK
 android-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-lib https://medium.com/@tangtungai/ef1b34126a5d

Slide 19

Slide 19 text

Compile Wear in Android Studio • Edit Gradle dependencies { compile fileTree(dir: compile compile } [Wearable module]

Slide 20

Slide 20 text

Packaging structure Android App Android App Code Resources Code Resources Wear App WearApp Module HandledApp Module

Slide 21

Slide 21 text

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 Compression https://developer.android.com/training/wearables/apps/packaging.html#PackageManually https://medium.com/@tangtungai/ef1b34126a5d

Slide 22

Slide 22 text

Packaging Wearables in Eclipse 1. Export and Sign Wearable Apps APK
 (eg: demowearapp.apk) #!/bin/bash cd ../wearable-1.1.0 android update lib-project --path . ant clean release cd ../DemoWearApp android update project --path . ant clean release key.store= key.store.password= key.alias= key.alias.password= config.logging=true ant.properties Generate build.xml [Wearable project]

Slide 23

Slide 23 text

Packaging Wearables in Eclipse 2. Add a meta-data tag in AndroidManifest.xml [Smartphone project]

Slide 24

Slide 24 text

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) 1 1.0 demowearapp [Smartphone project]

Slide 25

Slide 25 text

Packaging Wearables in Eclipse 5. Turn off Asset Compression http://stackoverflow.com/questions/7937368/how-to-pass-arguments-to-aapt-when-building-android-apk From /tools/ant/build.xml, search -package-resources Add this [Smartphone project]

Slide 26

Slide 26 text

[Smartphone module] dependencies { compile fileTree(dir: compile compile wearApp project( } Packaging Wearables in Android Studio • Edit Gradle

Slide 27

Slide 27 text

Code Examples AndroidWearable-Samples
 http://goo.gl/q8qfm8 DemoWearApp
 http://goo.gl/pIJzr4

Slide 28

Slide 28 text

Notifications

Slide 29

Slide 29 text

世新廣播電臺 Personal Works

Slide 30

Slide 30 text

Shih Hsin Radio Station • Actions • WearableExtender • Background • Page

Slide 31

Slide 31 text

Notification 整理 • Notification 到底要怎麼發? • 從⼿手機發送 • 同步到⼿手錶(含變更樣式) • 不同步到⼿手錶 • 從⼿手錶發送 mBuilder.setLocalOnly(true);

Slide 32

Slide 32 text

Notification 整理 • Notification 變更樣式? • 從⼿手機發送 • 設定⼿手機樣式,再變更⼿手錶樣式 • ⾃自訂樣式(只適⽤用於⼿手機) • 從⼿手錶發送 • ⾃自訂樣式(只適⽤用於⼿手錶) WearableExtender WearableExtender
 setDisplayIntent RemoteView

Slide 33

Slide 33 text

基本款 Notification NotificationCompat = new mBuilder mBuilder mBuilder Notification int NOTIFICATION_ID NotificationManager = getSystemService mNotificationManager 建⽴立 發送

Slide 34

Slide 34 text

Notification notification 基本款 Notification 舊寫法 (deprecated  in  API  level  11) 拜託別再寫了哈~

Slide 35

Slide 35 text

基本款 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();

Slide 36

Slide 36 text

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.html

Slide 37

Slide 37 text

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)

Slide 38

Slide 38 text

Notification Height Limit • Normal view layouts: 64 dp • Expanded view layouts: 256 dp. 256dp 64dp

Slide 39

Slide 39 text

WearableExtender

Slide 40

Slide 40 text

基本款 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();

Slide 41

Slide 41 text

RemoteControlClient Android  4.0  (API  14) METADATA_KEY_ARTIST

Slide 42

Slide 42 text

RemoteControlClient Android  4.0  (API  14) • Attribute Keys • METADATA_KEY_ARTIST • METADATA_KEY_TITLE • Attribute Keys • METADATA_KEY_TITLE • METADATA_KEY_ALBUM RemoteView

Slide 43

Slide 43 text

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(); 按鈕按下的⾏行為

Slide 44

Slide 44 text

24dp 48dp The Problem is…

Slide 45

Slide 45 text

NotificationCompat = new mBuilder mBuilder mBuilder mBuilder ( mBuilder ( NotificationCompat wExt ( Notification http://stackoverflow.com/questions/25026616/android-wear-action- item-icon-sizing-vs-phone-notification-action-item-sizing The solutions

Slide 46

Slide 46 text

Code Examples Wearable Notifications https://github.com/googlesamples/android-Notifications Basic Notifications https://github.com/googlesamples/android-BasicNotifications Custom Notifications https://github.com/googlesamples/android-CustomNotifications

Slide 47

Slide 47 text

• WatchViewStub • 指定 Round layout • 指定 Rect layout • BoxInsetLayout • 設定 app:layout_box="all" Layout http://developer.android.com/training/wearables/ui/layouts.html

Slide 48

Slide 48 text

Layout • Card • 繼承 CardFragment • CardScrollView + CardFrame http://developer.android.com/training/wearables/ui/cards.html

Slide 49

Slide 49 text

UI Structure

Slide 50

Slide 50 text

Data Layer

Slide 51

Slide 51 text

Google  Play  Services

Slide 52

Slide 52 text

Bluetooth Mini

Slide 53

Slide 53 text

Data Layer 資料傳輸層 • DataApi • MessageApi • NodeApi

Slide 54

Slide 54 text

Data Items • Path
 唯⼀一的字符串,必須以正斜線開始
 例如:/path/to/data • Payload
 ⼀一個字節數組,你可允許進⾏行對象的序列化 (Serialize) 與反序列化 (Deserialize)
 ⼤大⼩小不能超過100KB。 1BUI 1BZMPBE 100KB

Slide 55

Slide 55 text

連接⽅方式 • 在 Activity 中建⽴立連線,實作 Callback 監聽 • 使⽤用 WearableListenerService • Callback • DataApi.DataListener • MessageApi.MessageListener • NodeApi.NodeListener

Slide 56

Slide 56 text

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)

Slide 57

Slide 57 text

連接⽅方式 • onCreate() 建⽴立 GoogleApiClient,掛載 Callbacks @Override protected 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(); }

Slide 58

Slide 58 text

連線 Callback public void onConnected(Bundle connectionHint) public void onConnectionFailed(ConnectionResult result) • GoogleApiClient.ConnectionCallbacks • GoogleApiClient.OnConnectionFailedListener public void onConnectionSuspended(int cause) https://developer.android.com/google/auth/api-client.html

Slide 59

Slide 59 text

連接⽅方式 • onStart() 呼叫 connect() 做連線 @Override protected void onStart() { super.onStart(); if (!mResolvingError) { mGoogleApiClient.connect(); } } @Override //ConnectionCallbacks public 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

Slide 60

Slide 60 text

@Override protected 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,並且斷線

Slide 61

Slide 61 text

WearableListenerService • 在系統需要的時候就會⾃自動綁定 public class DataLayerListenerService extends WearableListenerService { @Override public void onDataChanged(DataEventBuffer dataEvents) { // Do Somthing } @Override public void onMessageReceived(MessageEvent messageEvent) { // Do Somthing } } AndroidManifest.xml

Slide 62

Slide 62 text

DataApi http://android-wear-docs.readthedocs.org/en/latest/data.html

Slide 63

Slide 63 text

DataItem private 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()); } @Override public void onDataChanged(DataEventBuffer dataEvents) { final List 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); } } } • 傳送 • 接收

Slide 64

Slide 64 text

MessageApi http://android-wear-docs.readthedocs.org/en/latest/sync.html

Slide 65

Slide 65 text

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 } } @Override public void onMessageReceived(MessageEvent messageEvent) { if (messageEvent.getPath().equals("/SAMPLE")) { final String message = new String(messageEvent.getData()); // Do Something } } • 傳送Message (AsyncTask) • 接收Message Message

Slide 66

Slide 66 text

Code Examples WearMessageBringFront
 http://goo.gl/jdKkHL WearDataLayerDemo
 http://goo.gl/HL84YQ DataLayer
 https://github.com/googlesamples/android-DataLayer

Slide 67

Slide 67 text

vs Apple Watch (WatchKit) Android Wear

Slide 68

Slide 68 text

Android Wear WatchKit Packaging structure Android App Android App Code Resources Code Resources Wear App WearApp Module HandledApp Module

Slide 69

Slide 69 text

Android Wear Google Play Services Google Play Services Android Device Controller Model View Mini Controller View Model Controller View Model App structure Android Wear WatchKit iOS App

Slide 70

Slide 70 text

好像少講了什麼?

Slide 71

Slide 71 text

震動 。 超⾃自然 的

Slide 72

Slide 72 text

震動 Vibrator mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); myVibrator.vibrate(100); AndroidManifest.xml

Slide 73

Slide 73 text

震動 mVibrator.vibrate(new long[]{80, 150, 80, 150, 80, 150}, -1); Repeat Pattern mVibrator 震動 Pattern 取消

Slide 74

Slide 74 text

Q & A

Slide 75

Slide 75 text

Troubleshooting: ⼿手錶 Offline 解決⽅方式 • Android Wear (設定 > 應⽤用程式) 1. 停⽤用 2. 清除資料 3. 啟⽤用 • Google Play 服務 (設定 > 應⽤用程式) 4. 清除所有資料(管理空間) • 硬體 5. 重置⼿手錶 6. ⼿手機重新啟動 http://melix.github.io/blog/2014/10/android-moto360.html $ adb devices List of devices attached dcfbbafd device localhost:4444 offline

Slide 76

Slide 76 text

Android Wear
 (設定 > 應⽤用程式) Google Play 服務 (設定 > 應⽤用程式 > 管理空間) 重置 Moto360 Troubleshooting: ⼿手錶 Offline 解決⽅方式

Slide 77

Slide 77 text

Troubleshooting: ⼿手錶 unauthorized 解決⽅方式 • 請使⽤用 Eclipse 做第⼀一次連接 $ adb devices List of devices attached dcfbbafd device localhost:4444 unauthorized