Android Wear

Download Report

Transcript Android Wear

Cosc 5/4730
Android Wear
Note
• This is all for Android Wear v5.x (api 21+)
– Which is wear version 1.1.0 to 1.3.0+ (as of feb
2016)
– V1.0.x was very limited by comparison (api 20)
• It was very difficult to even create a watchface.
• Android version of wear has also become
confusing all by itself as well.
devices and emulators
• You can setup a wear emulator and test most things
without the need for the physical device.
• But if you need the wear emulator to talk to a “phone”,
then you must connect a physical device/phone to it.
• Can connect to a device emulator. Odd, I know.
– Directions:
https://developer.android.com/training/wearables/apps/c
reating.html
– Basically,
• Install Android Wear on the device. Connect the device to the
Computer where you have the wear emulator running
• Start the wear app, in pairing, select Pear with Emulator in the
menu.
Studio
• Normally you select phone/tablet.
• If you are running something on the wear
device (ie watch), then you need to select
Wear
• If it will run on both, then select wear and
phone
Studio (2)
• Selecting Wear gives you the “wear Activities”
– I’ll show you Wear Activity and WatchFace
Studio (3)
• If you select both then
you will get “two”
projects
– Wear is the “watch”
code
– Mobile is the “phone”
code
What is Covered
• Wear is pretty large area of things we can do and
we will cover:
– Notifications
– Basic Watchfaces
• There is a lot more for watch face and information, say
calendar, weather etc.
– Basic app’s
• Enough so you can build an app and get started.
– Data Communication between wear device and
android device.
• Via the Google Service API
NOTIFICATIONS
Notifications
• For many of the applications, it is as simple a
sending a notification to the wearable device
– As well as device.
• Clearing a notification on wearable clears it on the phone as
well.
– You MUST use the NotificationCompat from the
support lib v4 (20 and above) and import the
following:
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import
android.support.v4.app.NotificationCompat.WearableExtender
;
Simple notification
• A simple one looks just like a normal
notification
– But the user will get on the wearable, and when
they swipe left o reveal the Open action, which
invokes the intent on the handheld device
Simple notification code
//create the intent to launch the notiactivity, then the pentingintent.
Intent viewIntent = new Intent(this, NotiActivity.class);
PendingIntent viewPendingIntent = PendingIntent.getActivity(this, 0, viewIntent, 0);
//Now create the notification. We must use the NotificationCompat or it will not work on the wearable.
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Simple Noti").setContentText("This is a simple notification")
.setContentIntent(viewPendingIntent);
// Get an instance of the NotificationManager service
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// Build the notification and issues it with notification manager.
NotificationManager.notify(notificationID, notificationBuilder.build());
Simple notification result
• The notification will look this this and then
swipe left to an open button
Adding your own button.
• Same as before, but use the addAction(…)
method.
– Both the device and wearable will show the action.
.addAction(R.drawable.ic_action_time, "take
Picutre", cameraPendingIntent);
– Where the Camera intent launches the camera.
Wearable only actions.
• Allows us to change the notification so it’s
different from the device and wearable
– Instead of addaction, we use .extend(…)
– .extend(new
WearableExtender().addAction(action)
• Where action is already build action
– NotificationCompat.Action action = new
NotificationCompat.Action.Builder(R.drawable.ic_action_time
,"take a Picutre", cameraPendingIntent).build();
– So the take a picture action only shows on the
wearable.
Other styles.
• As with notifications, we can also use a
BigTextStyle or InboxStyle (see notification inbox
before).
– BigTextStyles allows more text room and the
notification takes up most of the space on the
wearable.
• BigTextStyle bigStyle = new
NotificationCompat.BigTextStyle();
• bigStyle.bigText(eventDescription);
– And then in the builder
• .setStyle(bigStyle)
Voice Actions
• If the wear device accepts voice input, then
you can also add to your notifications.
– The user will talk to the wearable, because there is
no keyboard.
• Uses the RemoteInput class, via an intent and
add it as an action.
– This intent can be captured via the onCreate or
onNewIntent
• Note this can also be done with a broadcast receiver
and intent-filter not shown here.
Voice Actions (2)
• For the notification:
– With need id/key for this, so using this:
String EXTRA_VOICE_REPLY = "extra_voice_reply";
– create the remote input part for the notification.
RemoteInput remoteInput = new
RemoteInput.Builder(EXTRA_VOICE_REPLY)
.setLabel("Reply").build();
– Create the reply action and add the remote input
NotificationCompat.Action action = new
notificationCompat.Action.Builder( R.drawable.ic_action_map,
"Reply", replyPendingIntent)
.addRemoteInput(remoteInput).build();
– And add the action to the notification as before.
.extend(new WearableExtender().addAction(action)
Voice Actions example
Voice Actions (3)
• Now you get the intent in your activity and
pull out the string of text. It uses the Id/Key
from before.
Bundle remoteInput =
RemoteInput.getResultsFromIntent(getIntent());
if (remoteInput != null) {
info = remoteInput.getCharSequence( EXTRA_VOICE_REPLY
).toString();
}
Example code
• WearNotiDemo
– Shows the code via a subroutine for each of the
notifications that I listed.
• You can run this via a wearable emulator and
phone or with a wearable and phone.
– Note that the wearable emulator will need the
physical keyboard present checked, because there
is no voice, you have to type.
WATCHFACES
Studio
• When creating a watchface, you can get a lot of the
default settings.
– Analog or digital watch face
• With/without Interactive (ie what happens if the user touches it)
WatchFaces
• Studio will provide you with two possible watch face apps.
– Digital and analog. From there you can change them up as
needed, or create your own.
– You watchface must deal with ambient mode.
• There is where the screen is “darkened” and save battery life.
Normally remove all color and changes over to 1 minute update.
– Write for both round and square, plus insets on the bottom.
– Otherwise the layout and code is very similar to a standard
android app.
• Very helpful:
http://developer.android.com/training/wearables/watchfaces/index.html
A simple Example
• Design a Beer Time watch face.
– The time never changes and this shows the basics
• Using the Digital as the template, we have a
CanvasWatchFaceService.Engine
• We must declare a BroadcastReceiver for the
possible timezone change (and DayLightSaving
time as well).
– In our case, the code is empty. It’s still beer time.
A simple Example (2)
•
OnCreate(SurfaceHolder holder)
– Setup our variables.
– Set the WatchFace Style as well.
• initialize the watch face
setWatchFaceStyle(new WatchFaceStyle.Builder(beerWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
• Have the System show the time? No.
.setShowSystemUiTime(false)
• Where the battery and connection icons shows
.setStatusBarGravity(Gravity.TOP | Gravity.RIGHT)
• where 'OK google' shows
.setHotwordIndicatorGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL)
.build());
A simple Example (3)
• public void onPropertiesChanged(Bundle properties) {
– If we are in LowBitAbient mode or not
• Go very dark (or even the screen is blank)
• public void onAmbientModeChanged(boolean
inAmbientMode) {
– Setup some variables/fonts/colors for use in onDraw later.
– If inAbientMode
• Go black/white in the color screen
– Beer Face sets everything to Gray and Turns off AntiAliases for fonts
– Normally only minute and hour are shown.
– Else
• Use the “default” coloring. The watch face is “awake”.
– Use Yellow and antianlias fonts for beer face.
– Normally we would also see seconds (if applicable).
A simple Example (4)
• Dealing with both types of watches.
– public void onApplyWindowInsets(WindowInsets
insets) {
– Insets gives .isRound()
– Other resources to determine size
– Plus the inset at the bottom as well.
• So we setup our variables to use later in onDraw()
A simple Example (5)
• OnDraw(Canvas canvas, Rect bounds)
– Uses the canvas to draw with. Not openGL.
• See lecture from last semester.
– Example for beerWatch
/* draw your watch face */
String Beer = "Beer Time!";
float x = 0, y = 0;
x = bounds.width()/2 - mtextPaint.measureText(Beer)/2;
y = bounds.height()/2;
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(),
mBackgroundPaint);
canvas.drawText("Beer Time", x,y, mtextPaint);
Simple Example (6)
• onTimeTick() which is called every minute (or
quicker if not ambient mode)
@Override
public void onTimeTick() {
super.onTimeTick();
//normally change the time here, but beer
time is always the same.
invalidate();
}
Simple Example (7)
• Lastly, required code for the timezone change
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
registerReceiver(); //not blank, so do updates for the
timezone
} else {
unregisterReceiver(); //blank screen, so don’t care. Updates
when visiable.
}
}
WatchFace Example code
• 3 example watch face are provided
– BeerWatchFace
• Doesn’t show the time, instead “Beer time”
– Yellow in normal mode, gray in Ambient mode.
» Show the min needed to get a watch face working.
» Only updates once a minute.
– Digital
• Shows digital time,
– Normal mode, shows seconds, ambient mode just hour and
minute
WatchFaces Example code (2)
– Batman watchface
• Show date and time, plus a graphic
– In ambient mode, seconds are not shown and graphic is gray.
WEARABLE APP
Wear App’s
• As a Note, there is WearActivity, but it is only
supported on 5.1+
– It has an ambient mode, so that you app can stay
always on, similar to a watchface,
• You app must support an ambient mode as well.
– Not supported 4.4W and 5.0
– So I’m skipping over this one.
Wearable Apps
• This is a little bit of gmagic here, so the wear app
can be installed on the wear device.
• In Studio, New project
– Select Phone and Tablet (likely API 19)
– And a Wear API 20
• For the Mobile, select NO ACTIVITY.
– This is only a “wrapper app” for the wear app, to allow
the phone to install it on the wear device.
• For Wear select a Blank wear (always on is the
wearActivity one)
– It should give you a round and square layout.
Wearable Apps
• First issue: Round or Square?
Round or Square? Both!
• In the main activity layout your can use WatchViewStub
<android.support.wearable.view.WatchViewStub
…
android:id="@+id/watch_view_stub"
app:rectLayout="@layout/rect"
app:roundLayout="@layout/round"
tools:deviceIds="wear" >
</android.support.wearable.view.WatchViewStub>
• Where the rectLayout and roundLayout point to layouts
you can created for each device.
– Likely they will have the same Widgets/IDs for each layout, but
the way it looks will be different to deal with square or round.
Round or Square? Both! (2)
• Rect.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"… tools:deviceIds="wear_square" >
<TextView android:id="@+id/text“ …
android:text="@string/hello_square" />
</LinearLayout>
• Round.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
… tools:deviceIds="wear_round" >
<TextView android:id="@+id/text" …
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_round" />
</RelativeLayout>
Round or Square? Both! (2)
• In the activity, OnCreate:
setContentView(R.layout.activity_main);
WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new
WatchViewStub.OnLayoutInflatedListener() {
@Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}});
• In the onLayoutInflated, we know which layout has been inflated
and we use stub to find the widgets and setup like normal.
• But I’m skipping a lot of different layout and “new” widgets that
you have access to via the wearable library.
– Many are new to lollipop, in google glass as well. Like cards.
• Some widgets “sort of” described in the training. Others are not.
Example code
• WearApp
– Is my code based on ui app, where you can a
random number (click the checkmark for another
number).
Mobile app
• The mobile app is just a wrapper to install it
on the wear device. So it doesn’t need an
activity.
– Not if you have a real signing key it will create
everything for you.
– We a debug key we have to do this manually.
With a Debug key
• Make sure the mobile app has all the same
permissions the wear app
– Like vibrate if you used it.
• Make sure the build.gradle for both mobile
and wear have the same
• versionCode
• versionName
• PackageName
With a Debug key (2)
• Copy the apk from the wearable application
• See wear/build/outputs/apk/wear-debug.apk
• And copy into res/raw directory. Rename file to all
lower case, no special characters, use the App’s name
– You likely need to create a raw directory.
• Example: wearapp.apk
Wrapper app xml file
• Xml/wearable_app_desc.xml file
– This describe the apk to be installed onto the device.
<wearableApp package="edu.cs4730.wearapp">
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<rawPathResId>wearapp</rawPathResId>
</wearableApp>
– This match the build.grade information for the
wearable app.
• And the blue wearapp is the filename of the apk in raw/
Wrapper app androidManifest.xml
• This file will look something like this. No activity is listed,
because it not needed. The 2 lines in red are required.
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="edu.cs4730.wearapp" …>
<uses-sdk …/>
<application …>
<meta-data
android:name="com.google.android.wearable.beta.app"
android:resource="@xml/wearable_app_desc"/>
</application>
</manifest>
Wrapper app finally!
• “compile” and install it on the phone connected
to the wearable device.
• Not nothing will actually happen on the phone, because
there is no activity.
– Now check in the start section of the wearable for the
name of you wearable app.
• Hopefully you tested it thoroughly on the emulator, so it
doesn’t just crash!
• Remember, we can install the wear device
directory just a like a mobile device.
– So only necessary for “deployment” with a debug key.
DATA COMMINUCATION
Data Communication
• We this one, we will create both a wear and
mobile app.
– If you are installing this with a debug key
– Follow the previous step, but now there will also
be an activity as well.
Data communication (2)
• The device and wear can send messages via the
DataLayer, which comes from the GooglePlay services.
– In the build.gradle for both wear and mobile
• compile 'com.google.android.gms:play-services-wearable:8.4.0’
(or current version)
– To send a message
• You will need build a GoogleApiClient, that includes the wearable
API and the necessary listeners.
– Onconnected, onconnectionsuspeneded, and onconnectionfailed.
– And you send the message via your “message path”, which
I called, “/message_path”, but you can create your own
path name.
Data communication (3)
• We wanted this to be bi directional messages
– So the mobile and the wear app each have a
“send” method and a “receive” method.
– The receiver method receives an intent via a
broadcast receiver.
– The send method must use a thread, so it doesn’t
block the UI.
Sending a message
• Build a new GoogleApiClient that includes the
Wearable API
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
• Then you must use a thread to send the message, since
this is a blocking call.
MessageApi.SendMessageResult result =
Wearable.MessageApi.sendMessage(googleClient,
node.getId(), path, message.getBytes()).await();
– See the code for the whole thread.
Receiving a message
• Requires a WearableListenerService
• Simple service that has a onMessageReceived
method.
– Check to see if it’s on your “message path”
– Then deal with the message.
• In my code, it uses a local broadcast receiver to send a
message to the activity code, so it can be displayed on
the wearable and device screens.
Important note
• Both the mobile and wear code MUST have
the same applicationId in their build.gradle
files
– Otherwise it won’t work.
Example code
• There is an WearableDatalayer example that sends and
receives messages between a “phone” device and wearable
device.
– The device and wear have a send button that sends a message.
– The wear devices receives the method and then will send a
message back.
• The mobile only receives the method.
– So there isn’t an infinite loop of messages.
• Very useful references.
• http://android-wear-docs.readthedocs.org/en/latest/sync.html
• https://github.com/LarkspurCA/WearableMessage
• There are more references in the project as well.
Wear UIs
• In the com.google.android.support:wearable
library there are number widgets just for the
wear device
– BosInsetLayout which is a framelayout that
understands the shape (round,square, inset), which
“boxes” the widgets into a center square of a round
screen (or just a box for the square screen)
– CardFragment, CricledImageView,
confirmationActivity, DotsPageIndicator (for a
GridViewPager), WatchViewStub, WearableListView,
and there are more.
Voice
• Voice Actions can be added to a wear app, like
Voice Actions on a mobile device
– See
http://developer.android.com/training/wearables
/apps/voice.html#SystemProvided for the list of
intents
• Declare App-provided Voice Actions doesn’t
seem to work or their documentation is so
bad that I can’t get it to work.
Speech Recognition
• It works very much like the speech recognizer on the mobile
devices.
– Call the recognizer with an intent and it comes back via
onActivityResult
Intent intent = new Intent( RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
startActivityForResult(intent, SPEECH_REQUEST_CODE);
• And
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == SPEECH_REQUEST_CODE && resultCode == RESULT_OK) {
List<String> results = data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
String spokenText = results.get(0);
// Do something with spokenText
}}
References
• Android’s training site
– http://developer.android.com/training/wearables/app
s/index.html
– http://developer.android.com/training/buildingwearables.html
– http://developer.android.com/design/wear/principles
.html
– http://developer.android.com/training/wearables/app
s/voice.html
– http://developer.android.com/training/wearables/wat
ch-faces/index.html
Q&A