On Github justinribeiro / android-wear-introduction-gdg-devfest-2014
Justin Ribeiro justin@stickmanventures.com
@justinribeiro +Justin Ribeiro justinribeiro
Slides: https://goo.gl/dsbkIQ
Source: Engadget - "Microsoft's Android Wear keyboard has you drawing every letter"
Think about those seconds
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.app.NotificationCompat.WearableExtender;
// Let's build a notification NotificationCompat.Builder myNotification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_event) .setContentTitle("I'm a title!") .setContentText("DevFest 2014 Whooo Hooo") .setContentIntent(myIntent); // Get an instance of the NotificationManager service NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); // Build and send notificationManager.notify(myNotificationId, myNotification.build());
NotificationCompat.Builder myNotification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_event) .setContentTitle("I'm a title!") .setContentText("DevFest 2014 Whooo Hooo") .setContentIntent(myIntent) .addAction(R.drawable.ic_something, "More", myOtherIntent);
NotificationCompat.Action myAction = new NotificationCompat.Action.Builder(...) NotificationCompat.Builder myNotification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_event) .setContentTitle("I'm a title!") .setContentText("DevFest 2014 Whooo Hooo") .extend(new WearableExtender().addAction(myAction));
BigTextStyle bigStyle = new NotificationCompat.BigTextStyle(); bigStyle.bigText("I'm supposed to be long but that might not fit into this slide, yada yada yada"); NotificationCompat.Builder myNotification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_event) .setContentTitle("I'm a title!") .setContentText("DevFest 2014 Whooo Hooo") .addAction(R.drawable.ic_something, "More", myOtherIntent) .setStyle(bigStyle);
The big view...but tiny on this slide.
Yes, we should be using NotificationCompat.WearableExtender()
NotificationCompat.WearableExtender extendMyWearable = new NotificationCompat.WearableExtender() .setHintHideIcon(true) .setBackground(myMoreAwesomeImage); Notification myNotification = new NotificationCompat.Builder(someContext) .setContentTitle("Justin Says....") .setContentText("Speeling is hard") .setSmallIcon(R.drawable.ic_blahblah); .extend(extendMyWearable) .build();
Maybe you just need to send a little more without forcing the user to their handheld
// Create builder for the main notification NotificationCompat.Builder theMainNotification = new NotificationCompat.Builder(...); // Create the second page Notification theSecondPageNotification = new NotificationCompat.Builder(...); // The pages become friends Notification thePagesAll = new WearableExtender() .addPage(theSecondPageNotification) .extend(theMainNotification) .build(); // send them! notificationManager.notify(notificationId, thePagesAll);
Pages!
We should probably stack our notifications
// Our group for the stack final static String MY_GROUP_KEY = "group_things_such"; // Let's add this notification to this group Notification myNotification = new NotificationCompat.Builder(someContext) .setContentTitle("Get it together") .setContentText("I'm important news") .setSmallIcon(R.drawable.ic_blahblah); .setGroup(MY_GROUP_KEY) .build(); notificationManager.notify(notificationId1, myNotification);
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_large_icon); Notification summary = new NotificationCompat.Builder(mContext) .setContentTitle("2 new messages") .setSmallIcon(R.drawable.ic_small_icon) .setLargeIcon(largeIcon) .setStyle(new NotificationCompat.InboxStyle() .addLine("Alex Faaborg Check this out") .addLine("Jeff Chang Launch Party") .setBigContentTitle("2 new messages") .setSummaryText("johndoe@gmail.com")) .setGroup(MY_GROUP_KEY) .setGroupSummary(true) .build(); notificationManager.notify(notificationId3, summaryNotification);
Stacks!
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(myGoogleApiClient);
We can also listen and be notified if this connection changes
public interface NodeListener { void onPeerConnected(Node peer); void onPeerDisconnected(Node peer); }
See: NodeApi.NodeListener
// Method PendingResult sendMessage(GoogleApiClient client, String nodeId, String action, byte[] data); // Listener public interface MessageListener { void onMessageReceived(MessageEvent messageEvent); }
// Method PendingResult putDataItem(GoogleApiClient client, PutDataRequest request); PendingResult getDataItem(GoogleApiClient client, Uri uri);
// ... snip ... @Override public void onDataChanged(DataEventBuffer dataEvents) { for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_DELETED) { Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri()); } else if (event.getType() == DataEvent.TYPE_CHANGED) { Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri()); } } } // ... snip ...
Whoooa there partner: let's have a talk.
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.google.android.support:wearable:+' compile 'com.google.android.gms:play-services-wearable:+' }
Helps when you need seperate layouts for form factors
<android.support.wearable.view.WatchViewStub xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/watch_view_stub" android:layout_width="match_parent" android:layout_height="match_parent" app:rectLayout="@layout/rect_activity_wear" app:roundLayout="@layout/round_activity_wear"> </android.support.wearable.view.WatchViewStub>
Have to wait for inflations of view
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wear); WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { // Now you can access your views TextView tv = (TextView) stub.findViewById(R.id.text); } }); }
Allows single layout define for both form factors
<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@drawable/robot_background" android:layout_height="match_parent" android:layout_width="match_parent" android:padding="15dp"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp" app:layout_box="all"> <TextView android:gravity="center" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/sometext" android:textColor="@color/black" /> ...
<activity android:name="MyNoteActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="com.google.android.voicesearch.SELF_NOTE" /> </intent-filter> </activity>
<activity android:name="StartRunActivity" android:label="MyRunningApp"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>E;
// Key for the string that's delivered in the action's intent private static final String EXTRA_VOICE_REPLY = "extra_voice_reply"; RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY) .setLabel(replyLabel) .build(); // Create the reply action and add the remote input NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon, getString(R.string.label, replyPendingIntent)) .addRemoteInput(remoteInput) .build();
/** * Obtain the intent that started this activity by calling * Activity.getIntent() and pass it into this method to * get the associated voice input string. */ private CharSequence getMessageText(Intent intent) { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); if (remoteInput != null) { return remoteInput.getCharSequence(EXTRA_VOICE_REPLY); } } return null; }
private static final int SPEECH_REQUEST_CODE = 0; // Create an intent that can start the Speech Recognizer activity private void displaySpeechRecognizer() { Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); // Start the activity, the intent will be populated with the speech text startActivityForResult(intent, SPEECH_REQUEST_CODE); } // This callback is invoked when the Speech Recognizer returns. // This is where you process the intent and extract the speech text from the intent. @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SPEECH_REQUEST_CODE && resultCode == RESULT_OK) { List results = data.getStringArrayListExtra( RecognizerIntent.EXTRA_RESULTS); String spokenText = results.get(0); // Do something with spokenText } super.onActivityResult(requestCode, resultCode, data); }
We've only touched the surface, so much more!