August 11, 2015

Android Wear – Beyond Notifications Part 2

Written by

Part 2 of Gary Chang’s look ‘beyond notifications’ with his SpeeqNote app…

In the last post, we covered inter-device communications. This time we’re going to focus on the following:

  • Wear and phone intra-device, broadcast messaging to interact between background service and activities on the same device
  • Wear Speech to text recognition
  • Wearable List
  • Wear swipe actions (e.g. delete) using GridViewPager

Interaction between background services and foreground activities

Last time, I provided the reasoning behind using a background service to receive the incoming Messages and DataItems. Now I’ll go through how the service can interact with foreground activities, using local broadcast intents.

Referring to WearMessageListenerService, it registered WearNoteListListener as a DataApi.DataItemListener. When WearNoteListener has finished extracting the list of notes from the incoming DataItem, it sends a local brodcast intent:

Intent broadcastIntent = new Intent();
broadcastIntent.putParcelableArrayListExtra("noteList", items);
broadcastIntent.setAction("noteListResult");
LocalBroadcastManager.getInstance(wearCommsManager.getContext()).sendBroadcast(broadcastIntent);

This message is, as the name implies, broadcast to any and all interested parties (i.e. activities) however nothing happens unless that activity has previously registered a BroadcastReceiver that is interested in the “noteListResult” action. WearNoteListActivity has done just that:

noteListReceiver = new NoteListReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("noteListResult");
LocalBroadcastManager.getInstance(this).registerReceiver(noteListReceiver, filter);
private class NoteListReceiver extends BroadcastReceiver {
    public void onReceive(Context arg0, final Intent intent) {
        ArrayList notes = intent.getParcelableArrayListExtra("noteList");
        // update the list of notes on the screen 
    }
}

Note that a background service like WearMessageListenerService can also launch new activities and change navigation stacks, even when the phone or Wear app is backgrounded, so it provides a more flexible platform for receiving intra-device communications, more so than implementing listeners on each activity.
More information on this topic can be found at:

Speech to text recognition on a Wear device

It is very easy to implement speech to text recognition on a Wear device, and it is a very natural use case, Dick Tracy style!

To start the speech recogniser:

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
    RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
startActivityForResult(intent, SPEECH_RECOG_REQUEST_CODE);

Then implement the callback when the speech recogniser has finished doing its magic:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SPEECH_RECOG_REQUEST_CODE && resultCode == RESULT_OK) {
        List results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
        String speechRecognised = results.get(0);
        // do something with this String, like save it as a voice note!
    }
}

Being so simple, you’ll be wanting to implement voice recognition in all your Android Wear apps!

More information on this topic can be found at https://developer.android.com/training/wearables/apps/voice.html

 

aw2

Using WearableList to highlight the currently selected row on the Wear device

A normal ListView screen element works perfectly well on a Wear device, but the one drawback is there is no visual indication on the watch face that the row on screen is the one you are wanting to act on, e.g. there are three rows on screen – if you tap on the watch face, which row are you wanting? This is where WearableList comes in – it’s a special version of a ListView in that it provides callbacks so you can render the currently selected row with special attributes (e.g. brighter fonts, larger icons) while de-emphasising nearby rows above and below the currently selected one (e.g. semi-transparent text etc.)

The downside of the WearableList is that the row heights cannot be adjusted as the system has forced a fixed height, which does make for a more consistent scrolling experience.

Firstly, define in your layout xml that you want to use a WearableList rather than ListView eg. rect_wear_note_list.xml.

Next, you’ll need to extend a container layout like LinearLayout or RelativeLayout, that implements WearableListView’s OnCenterProximityListener:

public class NoteItemLayout extends LinearLayout implements
          WearableListView.OnCenterProximityListener {
    @Override
    protected void onFinishInflate() {
        // add references to the on screen fields you need access to via findById(..) here. 
        // These references will be later used in the two overridden methods below.
    }

    @Override
    public void onCenterPosition(boolean animate) {
        // style your on screen fields to highlight this row as it is currently the active row
        // eg. make the text bigger and bolder, enlarge the icons
    }

    @Override
    public void onNonCenterPosition(boolean animate) {
        // style your on screen fields to de-emphasise this is not the active row
        // eg. make text smaller and lower contrast and semi-transparent, make the icons smaller
    }
}

Lastly, WearableList uses the more complex but also better performing RecyclerView.Adapter, which separates the creation of the row views from the population of the fields for each row, recyling the views as necessary. Refer to WearableNoteListAdapter in the code.

More information on this topic is available at https://developer.android.com/training/wearables/ui/lists.html

 

androidwear6

Using GridViewPager to implement swipe actions

Android Wear uses the swipe gesture to reveal more actions that can performed on a particular item.

In this app, we reveal the delete action icon when you swipe a note detail to the left. This is implemented using a GridViewPager. In the code, refer to WearNoteDetailActivity’s DetailPagerAdapter inner class, which extends a GridViewPager.

The GridViewPager as its name implies, allows a 2D grid of content with a fixed number of rows and columns. In this app we have one row and two columns. The first column will be for the note details and the second column will be for the delete action icon. With multiple rows and columns the user will be able to scroll up and down by swiping vertically, and scroll sideways by swiping horizontally.

Any implementation of GridViewPager needs to override the following methods:

  • getColumnCount – returns the number of columns for the given row. This implies that you can have a different number of columns for each row across the 2D grid
  • getRowCount – returns the fixed number of rows for this grid
  • instantiateItem – instantiates and returns a view for the given row and column position
  • destroyItem – destroys the given view at the given row and column
  • isViewFromObject – determines whether the given view is associated with the given object

More information on this topic is available at https://developer.android.com/training/wearables/ui/2d-picker.html

These articles should hopefully have given you some starting points on how to implement Android Wear apps that provide richer interactions between the phone and the Wear device.

Tags: , ,

Categorised in: Digital, Innovation, Mobile

This post was written by Gary Chang