Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Wear Development

Android Wear Development

2015.01.28 @ Android Taipei

Johnny Sung

January 28, 2015
Tweet

More Decks by Johnny Sung

Other Decks in Technology

Transcript

  1. Agenda • Overview • Basic Setup • Notifications • Layout

    • Data Layer • Comparison with WatchKit
  2. Android Wear 設計理念 • Launched automatically (⾃自動啟動) • Glanceable (可⼀一眼瞥⾒見)

    • All about suggest and demand (推薦與需求) • Zero or low interaction (盡可能減少點擊滑動步驟)
  3. Debugging over Bluetooth • ⼿手機設定 Debugging over bluetooth • ⼿手錶設定

    ADB Debug
 & Debugging over bluetooth • 執⾏行 ConnectDebugWear.sh
 https://gist.github.com/j796160836/9b135a8de4c44846fd82
  4. 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
  5. 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
  6. 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
  7. Compile Wear in Android Studio • Edit Gradle dependencies {

    compile fileTree(dir: compile compile } [Wearable module]
  8. 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
  9. 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]
  10. Packaging Wearables in Eclipse 2. Add a meta-data tag in

    AndroidManifest.xml <application <meta-data </application> [Smartphone project]
  11. 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 <wearableApp <versionCode>1</versionCode> <versionName>1.0</versionName> <rawPathResId>demowearapp</rawPathResId> </wearableApp> [Smartphone project]
  12. Packaging Wearables in Eclipse 5. Turn off Asset Compression <target

    name= <do-only-if-not-library <aapt <res <res </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]
  13. Notification 整理 • Notification 變更樣式? • 從⼿手機發送 • 設定⼿手機樣式,再變更⼿手錶樣式 •

    ⾃自訂樣式(只適⽤用於⼿手機) • 從⼿手錶發送 • ⾃自訂樣式(只適⽤用於⼿手錶) WearableExtender WearableExtender
 setDisplayIntent RemoteView
  14. 基本款 Notification NotificationCompat = new mBuilder mBuilder mBuilder Notification int

    NOTIFICATION_ID NotificationManager = getSystemService mNotificationManager 建⽴立 發送
  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.html
  16. 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)
  17. Notification Height Limit • Normal view layouts: 64 dp •

    Expanded view layouts: 256 dp. 256dp 64dp
  18. 基本款 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();
  19. RemoteControlClient Android  4.0  (API  14) • Attribute Keys • METADATA_KEY_ARTIST

    • METADATA_KEY_TITLE • Attribute Keys • METADATA_KEY_TITLE • METADATA_KEY_ALBUM RemoteView
  20. 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(); 按鈕按下的⾏行為
  21. 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
  22. • WatchViewStub • 指定 Round layout • 指定 Rect layout

    • BoxInsetLayout • 設定 app:layout_box="all" Layout http://developer.android.com/training/wearables/ui/layouts.html
  23. Layout • Card • 繼承 CardFragment • CardScrollView + CardFrame

    http://developer.android.com/training/wearables/ui/cards.html
  24. 連接⽅方式 • 在 Activity 中建⽴立連線,實作 Callback 監聽 • 使⽤用 WearableListenerService

    • Callback • DataApi.DataListener • MessageApi.MessageListener • NodeApi.NodeListener
  25. 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)
  26. 連接⽅方式 • 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(); }
  27. 連線 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
  28. 連接⽅方式 • 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
  29. @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,並且斷線
  30. 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
  31. 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<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); } } } • 傳送 • 接收
  32. 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
  33. Android Wear WatchKit Packaging structure Android App Android App Code

    Resources Code Resources Wear App WearApp Module HandledApp Module
  34. 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
  35. 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
  36. Android Wear
 (設定 > 應⽤用程式) Google Play 服務 (設定 >

    應⽤用程式 > 管理空間) 重置 Moto360 Troubleshooting: ⼿手錶 Offline 解決⽅方式
  37. Troubleshooting: ⼿手錶 unauthorized 解決⽅方式 • 請使⽤用 Eclipse 做第⼀一次連接 $ adb

    devices List of devices attached dcfbbafd device localhost:4444 unauthorized