SlideShare une entreprise Scribd logo
1  sur  84
Télécharger pour lire hors ligne
+PeterFriese
@peterfriese
#AndroidWear
Design Principles
• Launched automatically
Design Principles
• Launched automatically
• Glanceable
Design Principles
• Launched automatically
• Glanceable
• Suggest and Demand
Design Principles
• Launched automatically
• Glanceable
• Suggest and Demand
• Zero or low interaction
Design Principles
Developing for
Android Wear
Notifications ApplicationsWatch Faces
Notifications
Simple Notifications
Look, ma - no work required!
Intent viewIntent = new Intent(context, DummyActivity.class);



PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);

Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.setContentIntent(viewPendingIntent)

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
Simple Notifications
Can we do better?
BigPictureStyle
Enhanced Notifications
Intent viewIntent = new Intent(context, DummyActivity.class);



PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);

Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.setStyle(

new NotificationCompat.BigPictureStyle()

.bigPicture(BitmapFactory.decodeResource(context.getResources(),
R.drawable.sanfrancisco))

.setBigContentTitle("Flight AW123 is ready to board.")

.setSummaryText("Please proceed to gate C 17 to board. Have a nice flight!"))

.setContentIntent(viewPendingIntent)

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
BigPictureStyle
Intent viewIntent = new Intent(context, DummyActivity.class);



PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);

Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.setStyle(

new NotificationCompat.BigPictureStyle()

.bigPicture(BitmapFactory.decodeResource(context.getResources(),
R.drawable.sanfrancisco))

.setBigContentTitle("Flight AW123 is ready to board.")

.setSummaryText("Please proceed to gate C 17 to board. Have a nice flight!"))

.setContentIntent(viewPendingIntent)

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
BigPictureStyle
Create BigPictureStyle
Pages
Enhanced Notifications
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

.setContentTitle("Your seat")

.setContentText("17A")

.extend(new NotificationCompat.WearableExtender()

.setBackground(BitmapFactory.decodeResource(context.getResources(),
R.drawable.a380_seat)))

.build());
sendNotification()
Pages
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

.setContentTitle("Your seat")

.setContentText("17A")

.extend(new NotificationCompat.WearableExtender()

.setBackground(BitmapFactory.decodeResource(context.getResources(),
R.drawable.a380_seat)))

.build());
sendNotification()
Pages
Create page with title
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

.setContentTitle("Your seat")

.setContentText("17A")

.extend(new NotificationCompat.WearableExtender()

.setBackground(BitmapFactory.decodeResource(context.getResources(),
R.drawable.a380_seat)))

.build());
sendNotification()
Pages
Set background image
pages.add(new NotificationCompat.Builder(context)

.extend(new NotificationCompat.WearableExtender()

.setHintShowBackgroundOnly(true)
.setHintAvoidBackgroundClipping(true)

.setHintScreenTimeout(NotificationCompat.WearableExtender.SCREEN_TIMEOUT_LONG)

.setBackground(
BitmapFactory.decodeResource(
context.getResources(),
R.drawable.qrcode)))

.build());
sendNotification()
Background Only Pages
pages.add(new NotificationCompat.Builder(context)

.extend(new NotificationCompat.WearableExtender()

.setHintShowBackgroundOnly(true)
.setHintAvoidBackgroundClipping(true)

.setHintScreenTimeout(NotificationCompat.WearableExtender.SCREEN_TIMEOUT_LONG)

.setBackground(
BitmapFactory.decodeResource(
context.getResources(),
R.drawable.qrcode)))

.build());
sendNotification()
Background Only Pages
Show background only
Don’t clip on round displays
Extended timeout
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

// ... (set properties)

.build());
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentIntent(viewPendingIntent)

.extend(new NotificationCompat.WearableExtender()

.addPages(pages))

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
Adding Pages to Notifications
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

// ... (set properties)

.build());
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentIntent(viewPendingIntent)

.extend(new NotificationCompat.WearableExtender()

.addPages(pages))

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
Adding Pages to Notifications
Build pages
ArrayList<Notification> pages = new ArrayList<Notification>();

pages.add(new NotificationCompat.Builder(context)

// ... (set properties)

.build());
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentIntent(viewPendingIntent)

.extend(new NotificationCompat.WearableExtender()

.addPages(pages))

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);

sendNotification()
Adding Pages to Notifications
Add pages to notification
Voice Input
Enhanced Notifications
// Feedback intent

Intent replyIntent = new Intent(context, DummyActivity.class);

PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);



String replyLabel = context.getResources().getString(R.string.reply_label);

String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

sendNotification()
Voice Input
// Feedback intent

Intent replyIntent = new Intent(context, DummyActivity.class);

PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);



String replyLabel = context.getResources().getString(R.string.reply_label);

String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

sendNotification()
Voice Input
Create pending intent
// Feedback intent

Intent replyIntent = new Intent(context, DummyActivity.class);

PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);



String replyLabel = context.getResources().getString(R.string.reply_label);

String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

sendNotification()
Voice Input
Create RemoteInput with canned responses
// Feedback intent

Intent replyIntent = new Intent(context, DummyActivity.class);

PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);



String replyLabel = context.getResources().getString(R.string.reply_label);

String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

sendNotification()
Voice Input
Create wearable action
String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.extend(new NotificationCompat.WearableExtender()

.addPages(pages)

.addAction(replyAction))

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);


sendNotification()
Voice Input
Create notification
String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);

RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)

.setLabel(replyLabel)

.setChoices(cannedResponses)

.build();



NotificationCompat.Action replyAction =

new NotificationCompat.Action.Builder(
R.drawable.chatbubble_working,
replyLabel,
replyPendingIntent)

.addRemoteInput(remoteInput)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.extend(new NotificationCompat.WearableExtender()

.addPages(pages)

.addAction(replyAction))

.build();



NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

notificationManager.notify(notificationId++, notification);


sendNotification()
Voice Input
Send notification
Intent intent = getIntent();

if (intent != null) {
Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);

if (remoteInputResults != null) {

CharSequence utterance =
remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY);


Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();

}
}
ReceivingActivity.onCreate()
Receiving Voice Input
Intent intent = getIntent();

if (intent != null) {
Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);

if (remoteInputResults != null) {

CharSequence utterance =
remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY);


Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();

}
}
ReceivingActivity.onCreate()
Receiving Voice Input
Get remote input
Intent intent = getIntent();

if (intent != null) {
Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);

if (remoteInputResults != null) {

CharSequence utterance =
remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY);


Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();

}
}
ReceivingActivity.onCreate()
Receiving Voice Input
Unpack voice reply
Actions
Enhanced Notifications
Intent mapIntent = new Intent(Intent.ACTION_VIEW);

Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));

mapIntent.setData(geoUri);

PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0);
sendNotification()
Actions
Intent mapIntent = new Intent(Intent.ACTION_VIEW);

Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));

mapIntent.setData(geoUri);

PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0);



NotificationCompat.Action walkingDirectionsAction =

new NotificationCompat.Action.Builder(
R.drawable.ic_full_directions_walking, "Directions to gate", mapPendingIntent)

.build();
sendNotification()
Actions
Intent mapIntent = new Intent(Intent.ACTION_VIEW);

Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));

mapIntent.setData(geoUri);

PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0);



NotificationCompat.Action walkingDirectionsAction =

new NotificationCompat.Action.Builder(
R.drawable.ic_full_directions_walking, "Directions to gate", mapPendingIntent)

.build();
Notification notification = new NotificationCompat.Builder(context)

.setSmallIcon(R.drawable.ic_launcher)

.setSmallIcon(R.drawable.plane)

.setContentTitle(String.format("Flight AW123 is ready to board", notificationId))

.setContentText("Please proceed to gate C 17 to board. Have a nice flight!")

.addAction(walkingDirectionsAction)

.extend(new NotificationCompat.WearableExtender()

.addPages(pages)

.addAction(replyAction)

.addAction(walkingDirectionsAction))

.build();

sendNotification()
Actions
Applications
Launching
Wearable apps
Using app-provided
voice actions
Using the start
menu
<application

android:icon="@drawable/greenlinelogo"

android:label="@string/app_name"

android:theme="@android:style/Theme.DeviceDefault" >

<activity

android:name="de.peterfriese.weartravel.MainActivity"

android:label="@string/app_name_voice" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />



<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

AndroidManifest.xml
Launching
<application

android:icon="@drawable/greenlinelogo"

android:label="@string/app_name"

android:theme="@android:style/Theme.DeviceDefault" >

<activity

android:name="de.peterfriese.weartravel.MainActivity"

android:label="@string/app_name_voice" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />



<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

AndroidManifest.xml
Launching
Label for voice action
Custom Layouts
Wearable Apps
<android.support.wearable.view.BoxInsetLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_height="match_parent"

android:layout_width="match_parent">



<FrameLayout

android:id="@+id/frame_layout"

android:layout_height="match_parent"

android:layout_width="match_parent"

app:layout_box="left|bottom|right">



<android.support.wearable.view.WearableListView

android:id="@+id/checkin_list"

android:layout_height="match_parent"

android:layout_width="match_parent">

</android.support.wearable.view.WearableListView>

</FrameLayout>

</android.support.wearable.view.BoxInsetLayout>
activity_checkin.xml
Layout - List
<android.support.wearable.view.BoxInsetLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_height="match_parent"

android:layout_width="match_parent">



<FrameLayout

android:id="@+id/frame_layout"

android:layout_height="match_parent"

android:layout_width="match_parent"

app:layout_box="left|bottom|right">



<android.support.wearable.view.WearableListView

android:id="@+id/checkin_list"

android:layout_height="match_parent"

android:layout_width="match_parent">

</android.support.wearable.view.WearableListView>

</FrameLayout>

</android.support.wearable.view.BoxInsetLayout>
activity_checkin.xml
Layout - List
<?xml version="1.0" encoding="utf-8"?>

<merge xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto">



<android.support.wearable.view.CircledImageView

android:id="@+id/image"

android:alpha="0.5"

android:layout_height="52dp"

android:layout_marginLeft="16dp"

android:layout_width="52dp"

app:circle_border_color="#FFFFFFFF"

app:circle_border_width="2dp"

app:circle_color="#00000000"

/>



<TextView

android:id="@+id/text"

android:alpha="0.5"

android:fontFamily="sans-serif-condensed-light"

android:gravity="center_vertical"

android:layout_height="52dp"

android:layout_marginLeft="72dp"

checkin_listview_item.xml
Layout - Item
<?xml version="1.0" encoding="utf-8"?>

<merge xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto">



<android.support.wearable.view.CircledImageView

android:id="@+id/image"

android:alpha="0.5"

android:layout_height="52dp"

android:layout_marginLeft="16dp"

android:layout_width="52dp"

app:circle_border_color="#FFFFFFFF"

app:circle_border_width="2dp"

app:circle_color="#00000000"

/>



<TextView

android:id="@+id/text"

android:alpha="0.5"

android:fontFamily="sans-serif-condensed-light"

android:gravity="center_vertical"

android:layout_height="52dp"

android:layout_marginLeft="72dp"

android:layout_marginRight="16dp"

android:layout_width="wrap_content"

android:textColor="@color/white"

android:textSize="14sp"

/>

</merge>
Layout - Item
checkin_listview_item.xml
private final class MyItemView extends FrameLayout implements
WearableListView.OnCenterProximityListener {



final CircledImageView image;

final TextView text;



public MyItemView(Context context) {

super(context);

View.inflate(context, R.layout.checkin_listview_item, this);

image = (CircledImageView) findViewById(R.id.image);

text = (TextView) findViewById(R.id.text);

}



@Override

public void onCenterPosition(boolean b) {

image.animate().scaleX(1f).scaleY(1f).alpha(1);

text.animate().scaleX(1f).scaleY(1f).alpha(1);

}



@Override

public void onNonCenterPosition(boolean b) {

image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);

CheckInActivity.java
MyViewItem
private final class MyItemView extends FrameLayout implements
WearableListView.OnCenterProximityListener {



final CircledImageView image;

final TextView text;



public MyItemView(Context context) {

super(context);

View.inflate(context, R.layout.checkin_listview_item, this);

image = (CircledImageView) findViewById(R.id.image);

text = (TextView) findViewById(R.id.text);

}



@Override

public void onCenterPosition(boolean b) {

image.animate().scaleX(1f).scaleY(1f).alpha(1);

text.animate().scaleX(1f).scaleY(1f).alpha(1);

}



@Override

public void onNonCenterPosition(boolean b) {

image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);

CheckInActivity.java
MyViewItem
private final class MyItemView extends FrameLayout implements
WearableListView.OnCenterProximityListener {



final CircledImageView image;

final TextView text;



public MyItemView(Context context) {

super(context);

View.inflate(context, R.layout.checkin_listview_item, this);

image = (CircledImageView) findViewById(R.id.image);

text = (TextView) findViewById(R.id.text);

}



@Override

public void onCenterPosition(boolean b) {

image.animate().scaleX(1f).scaleY(1f).alpha(1);

text.animate().scaleX(1f).scaleY(1f).alpha(1);

}



@Override

public void onNonCenterPosition(boolean b) {

image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);

text.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);

}

}
CheckInActivity.java
MyViewItem
public class CheckInActivity extends Activity implements WearableListView.ClickListener {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_checkin);



MyListAdapter adapter = new MyListAdapter();



WearableListView listView = (WearableListView) findViewById(R.id.checkin_list);

listView.setAdapter(adapter);

listView.setClickListener(CheckInActivity.this);

}



@Override

public void onClick(WearableListView.ViewHolder viewHolder) {

Toast.makeText(this, String.format("You selected item #%s",
viewHolder.getPosition()), Toast.LENGTH_SHORT).show();

}



@Override

public void onTopEmptyRegionClick() {

CheckInActivity.java
Activity
public class CheckInActivity extends Activity implements WearableListView.ClickListener {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_checkin);



MyListAdapter adapter = new MyListAdapter();



WearableListView listView = (WearableListView) findViewById(R.id.checkin_list);

listView.setAdapter(adapter);

listView.setClickListener(CheckInActivity.this);

}



@Override

public void onClick(WearableListView.ViewHolder viewHolder) {

Toast.makeText(this, String.format("You selected item #%s",
viewHolder.getPosition()), Toast.LENGTH_SHORT).show();

}



@Override

public void onTopEmptyRegionClick() {

Toast.makeText(this, "You tapped into the empty area above the list",
Toast.LENGTH_SHORT).show();

}

CheckInActivity.java
Activity
Watch Faces
Design Principles
• Square vs round
Design Principles
• Square vs round
• Ambient mode / low-bit
Design Principles
• Square vs round
• Ambient mode / low-bit
• Legibility
Design Principles
56° - Cloudy
56° - Cloudy
Developing
Watch Faces
• Start using a sample
Developing
Watch Faces
• Start using a sample
• Add a new wearable module
Developing
Watch Faces
Architecture
Wearable App Mobile App
CanvasWatchFaceService
ConfigActivity
Engine
ConfigActivityWearableListenerService
Architecture
Wearable App
CanvasWatchFaceService
ConfigActivity
Engine
WearableListenerService
Engine
onCreate
onPropertiesChanged
onDraw
onTimeTick
onAmbientModeChanged
onVisibilityChanged
@Override

public void onCreate(SurfaceHolder holder) {

super.onCreate(holder);



setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)

.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)

.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)

.setShowSystemUiTime(false)

.build());



Resources resources = AnalogWatchFaceService.this.getResources();

Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);

mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();



mHourPaint = new Paint();

mHourPaint.setARGB(255, 200, 200, 200);

mHourPaint.setStrokeWidth(5.f);

mHourPaint.setAntiAlias(true);

mHourPaint.setStrokeCap(Paint.Cap.ROUND);
onCreate
Lifecycle - initialise watch face elements
@Override

public void onCreate(SurfaceHolder holder) {

super.onCreate(holder);



setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)

.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)

.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)

.setShowSystemUiTime(false)

.build());



Resources resources = AnalogWatchFaceService.this.getResources();

Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);

mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();



mHourPaint = new Paint();

mHourPaint.setARGB(255, 200, 200, 200);

mHourPaint.setStrokeWidth(5.f);

mHourPaint.setAntiAlias(true);

mHourPaint.setStrokeCap(Paint.Cap.ROUND);
onCreate
Lifecycle - initialise watch face elements
Single-line peek card
Do not show system time
Show background briefly for
interruptive cards
@Override

public void onCreate(SurfaceHolder holder) {

super.onCreate(holder);



setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)

.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)

.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)

.setShowSystemUiTime(false)

.build());



Resources resources = AnalogWatchFaceService.this.getResources();

Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);

mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();



mHourPaint = new Paint();

mHourPaint.setARGB(255, 200, 200, 200);

mHourPaint.setStrokeWidth(5.f);

mHourPaint.setAntiAlias(true);

mHourPaint.setStrokeCap(Paint.Cap.ROUND);
onCreate
Lifecycle - initialise watch face elements
Load background image
@Override

public void onCreate(SurfaceHolder holder) {

super.onCreate(holder);



setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)

.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)

.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)

.setShowSystemUiTime(false)

.build());



Resources resources = AnalogWatchFaceService.this.getResources();

Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);

mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();



mHourPaint = new Paint();

mHourPaint.setARGB(255, 200, 200, 200);

mHourPaint.setStrokeWidth(5.f);

mHourPaint.setAntiAlias(true);

mHourPaint.setStrokeCap(Paint.Cap.ROUND);
onCreate
Lifecycle - initialise watch face elements
Create styles for graphic objects
@Override

public void onDraw(Canvas canvas, Rect bounds) {

mTime.setToNow();



canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
float centerX = width / 2f;

float centerY = height / 2f;



float innerTickRadius = centerX - 10;

float outerTickRadius = centerX;

for (int tickIndex = 0; tickIndex < 12; tickIndex++) {

float tickRot = (float) (tickIndex * Math.PI * 2 / 12);

float innerX = (float) Math.sin(tickRot) * innerTickRadius;

float innerY = (float) -Math.cos(tickRot) * innerTickRadius;

float outerX = (float) Math.sin(tickRot) * outerTickRadius;

float outerY = (float) -Math.cos(tickRot) * outerTickRadius;

canvas.drawLine(centerX + innerX, centerY + innerY,

centerX + outerX, centerY + outerY, mTickPaint);

}



float secRot = mTime.second / 30f * (float) Math.PI;

onDraw
Lifecycle - draw the watch face
@Override

public void onDraw(Canvas canvas, Rect bounds) {

mTime.setToNow();



canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
float centerX = width / 2f;

float centerY = height / 2f;



float innerTickRadius = centerX - 10;

float outerTickRadius = centerX;

for (int tickIndex = 0; tickIndex < 12; tickIndex++) {

float tickRot = (float) (tickIndex * Math.PI * 2 / 12);

float innerX = (float) Math.sin(tickRot) * innerTickRadius;

float innerY = (float) -Math.cos(tickRot) * innerTickRadius;

float outerX = (float) Math.sin(tickRot) * outerTickRadius;

float outerY = (float) -Math.cos(tickRot) * outerTickRadius;

canvas.drawLine(centerX + innerX, centerY + innerY,

centerX + outerX, centerY + outerY, mTickPaint);

}



float secRot = mTime.second / 30f * (float) Math.PI;

onDraw
Lifecycle - draw the watch face
Update time
Draw background image
@Override

public void onDraw(Canvas canvas, Rect bounds) {

mTime.setToNow();



canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
float centerX = width / 2f;

float centerY = height / 2f;



float innerTickRadius = centerX - 10;

float outerTickRadius = centerX;

for (int tickIndex = 0; tickIndex < 12; tickIndex++) {

float tickRot = (float) (tickIndex * Math.PI * 2 / 12);

float innerX = (float) Math.sin(tickRot) * innerTickRadius;

float innerY = (float) -Math.cos(tickRot) * innerTickRadius;

float outerX = (float) Math.sin(tickRot) * outerTickRadius;

float outerY = (float) -Math.cos(tickRot) * outerTickRadius;

canvas.drawLine(centerX + innerX, centerY + innerY,

centerX + outerX, centerY + outerY, mTickPaint);

}



float secRot = mTime.second / 30f * (float) Math.PI;

onDraw
Lifecycle - draw the watch face
Draw the ticks
float centerX = width / 2f;

float centerY = height / 2f;



float innerTickRadius = centerX - 10;

float outerTickRadius = centerX;

for (int tickIndex = 0; tickIndex < 12; tickIndex++) {

float tickRot = (float) (tickIndex * Math.PI * 2 / 12);

float innerX = (float) Math.sin(tickRot) * innerTickRadius;

float innerY = (float) -Math.cos(tickRot) * innerTickRadius;

float outerX = (float) Math.sin(tickRot) * outerTickRadius;

float outerY = (float) -Math.cos(tickRot) * outerTickRadius;

canvas.drawLine(centerX + innerX, centerY + innerY,

centerX + outerX, centerY + outerY, mTickPaint);

}



float secRot = mTime.second / 30f * (float) Math.PI;

int minutes = mTime.minute;

float minRot = minutes / 30f * (float) Math.PI;

float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI;



float secLength = centerX - 20;

float minLength = centerX - 40;

float hrLength = centerX - 80;

if (!isInAmbientMode()) {

float secX = (float) Math.sin(secRot) * secLength;

float secY = (float) -Math.cos(secRot) * secLength;

canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);

}



onDraw
Lifecycle - draw the watch face
Determine hands geometry
float outerX = (float) Math.sin(tickRot) * outerTickRadius;

float outerY = (float) -Math.cos(tickRot) * outerTickRadius;

canvas.drawLine(centerX + innerX, centerY + innerY,

centerX + outerX, centerY + outerY, mTickPaint);

}



float secRot = mTime.second / 30f * (float) Math.PI;

int minutes = mTime.minute;

float minRot = minutes / 30f * (float) Math.PI;

float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI;



float secLength = centerX - 20;

float minLength = centerX - 40;

float hrLength = centerX - 80;

if (!isInAmbientMode()) {

float secX = (float) Math.sin(secRot) * secLength;

float secY = (float) -Math.cos(secRot) * secLength;

canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);

}



float minX = (float) Math.sin(minRot) * minLength;

float minY = (float) -Math.cos(minRot) * minLength;

canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mMinutePaint);



float hrX = (float) Math.sin(hrRot) * hrLength;

float hrY = (float) -Math.cos(hrRot) * hrLength;

canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHourPaint);

}
onDraw
Lifecycle - draw the watch face
Don’t draw seconds when in
ambient mode
Draw minutes hand
Draw hours hand
Watch Faces
Demo
+PeterFriese
@
Thank you!
#AndroidWear
W
e’re
hiring!
+PeterFriese
@
Q & A
#AndroidWear
W
e’re
hiring!
W
e’re
hiring!
Introduction to Android Wear

Contenu connexe

Tendances

ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013
Mathias Seguy
 
Звиад Кардава "Android Things + Google Weave"
Звиад Кардава "Android Things + Google Weave" Звиад Кардава "Android Things + Google Weave"
Звиад Кардава "Android Things + Google Weave"
IT Event
 
CiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForceCiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForce
Ciklum Ukraine
 

Tendances (20)

ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React
 
Android Wear Essentials
Android Wear EssentialsAndroid Wear Essentials
Android Wear Essentials
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blink
 
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VRHow to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
 
Android Wear: A Developer's Perspective
Android Wear: A Developer's PerspectiveAndroid Wear: A Developer's Perspective
Android Wear: A Developer's Perspective
 
Звиад Кардава "Android Things + Google Weave"
Звиад Кардава "Android Things + Google Weave" Звиад Кардава "Android Things + Google Weave"
Звиад Кардава "Android Things + Google Weave"
 
Dojo and Adobe AIR
Dojo and Adobe AIRDojo and Adobe AIR
Dojo and Adobe AIR
 
Android wearpp
Android wearppAndroid wearpp
Android wearpp
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming En
 
Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018
 
CiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForceCiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForce
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
 
Leaving Interface Builder Behind
Leaving Interface Builder BehindLeaving Interface Builder Behind
Leaving Interface Builder Behind
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)
 
I phone勉強会 (2011.11.23)
I phone勉強会 (2011.11.23)I phone勉強会 (2011.11.23)
I phone勉強会 (2011.11.23)
 

Similaire à Introduction to Android Wear

Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
Making it fit - DroidCon Paris 18 june 2013
Making it fit - DroidCon Paris 18 june 2013Making it fit - DroidCon Paris 18 june 2013
Making it fit - DroidCon Paris 18 june 2013
Paris Android User Group
 

Similaire à Introduction to Android Wear (20)

Introduction to Android Wear
Introduction to Android WearIntroduction to Android Wear
Introduction to Android Wear
 
Introduction to Android Wear - Peter Friese
Introduction to Android Wear - Peter FrieseIntroduction to Android Wear - Peter Friese
Introduction to Android Wear - Peter Friese
 
Developing for android wear
Developing for android wearDeveloping for android wear
Developing for android wear
 
Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)
 
"It's Time" - Android Wear codelab - GDG MeetsU - L'Aquila
"It's Time" - Android Wear codelab - GDG MeetsU - L'Aquila"It's Time" - Android Wear codelab - GDG MeetsU - L'Aquila
"It's Time" - Android Wear codelab - GDG MeetsU - L'Aquila
 
Session #8 adding magic to your app
Session #8  adding magic to your appSession #8  adding magic to your app
Session #8 adding magic to your app
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CN
 
Developing AIR for Android with Flash Professional
Developing AIR for Android with Flash ProfessionalDeveloping AIR for Android with Flash Professional
Developing AIR for Android with Flash Professional
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app development
 
Developer Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersDeveloper Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for Beginners
 
Android Oreo
Android OreoAndroid Oreo
Android Oreo
 
Developing AIR for Android with Flash Professional CS5
Developing AIR for Android with Flash Professional CS5Developing AIR for Android with Flash Professional CS5
Developing AIR for Android with Flash Professional CS5
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Desenvolver para Chromecast
Desenvolver para ChromecastDesenvolver para Chromecast
Desenvolver para Chromecast
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Android Wearables ii
Android Wearables iiAndroid Wearables ii
Android Wearables ii
 
mobl
moblmobl
mobl
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
 
Advancing the UI — Part 1: Look, Motion, and Gestures
Advancing the UI — Part 1: Look, Motion, and GesturesAdvancing the UI — Part 1: Look, Motion, and Gestures
Advancing the UI — Part 1: Look, Motion, and Gestures
 
Making it fit - DroidCon Paris 18 june 2013
Making it fit - DroidCon Paris 18 june 2013Making it fit - DroidCon Paris 18 june 2013
Making it fit - DroidCon Paris 18 june 2013
 

Plus de Peter Friese

Do Androids Dream of Electric Sheep
Do Androids Dream of Electric SheepDo Androids Dream of Electric Sheep
Do Androids Dream of Electric Sheep
Peter Friese
 

Plus de Peter Friese (20)

Building Reusable SwiftUI Components
Building Reusable SwiftUI ComponentsBuilding Reusable SwiftUI Components
Building Reusable SwiftUI Components
 
Firebase & SwiftUI Workshop
Firebase & SwiftUI WorkshopFirebase & SwiftUI Workshop
Firebase & SwiftUI Workshop
 
Building Reusable SwiftUI Components
Building Reusable SwiftUI ComponentsBuilding Reusable SwiftUI Components
Building Reusable SwiftUI Components
 
Firebase for Apple Developers - SwiftHeroes
Firebase for Apple Developers - SwiftHeroesFirebase for Apple Developers - SwiftHeroes
Firebase for Apple Developers - SwiftHeroes
 
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in Swift
 
Firebase for Apple Developers
Firebase for Apple DevelopersFirebase for Apple Developers
Firebase for Apple Developers
 
Building Apps with SwiftUI and Firebase
Building Apps with SwiftUI and FirebaseBuilding Apps with SwiftUI and Firebase
Building Apps with SwiftUI and Firebase
 
Rapid Application Development with SwiftUI and Firebase
Rapid Application Development with SwiftUI and FirebaseRapid Application Development with SwiftUI and Firebase
Rapid Application Development with SwiftUI and Firebase
 
Rapid Application Development with SwiftUI and Firebase
Rapid Application Development with SwiftUI and FirebaseRapid Application Development with SwiftUI and Firebase
Rapid Application Development with SwiftUI and Firebase
 
6 Things You Didn't Know About Firebase Auth
6 Things You Didn't Know About Firebase Auth6 Things You Didn't Know About Firebase Auth
6 Things You Didn't Know About Firebase Auth
 
Five Things You Didn't Know About Firebase Auth
Five Things You Didn't Know About Firebase AuthFive Things You Didn't Know About Firebase Auth
Five Things You Didn't Know About Firebase Auth
 
Building High-Quality Apps for Google Assistant
Building High-Quality Apps for Google AssistantBuilding High-Quality Apps for Google Assistant
Building High-Quality Apps for Google Assistant
 
Building Conversational Experiences with Actions on Google
Building Conversational Experiences with Actions on Google Building Conversational Experiences with Actions on Google
Building Conversational Experiences with Actions on Google
 
Building Conversational Experiences with Actions on Google
Building Conversational Experiences with Actions on GoogleBuilding Conversational Experiences with Actions on Google
Building Conversational Experiences with Actions on Google
 
What's new in Android Wear 2.0
What's new in Android Wear 2.0What's new in Android Wear 2.0
What's new in Android Wear 2.0
 
Google+ for Mobile Apps on iOS and Android
Google+ for Mobile Apps on iOS and AndroidGoogle+ for Mobile Apps on iOS and Android
Google+ for Mobile Apps on iOS and Android
 
Cross-Platform Authentication with Google+ Sign-In
Cross-Platform Authentication with Google+ Sign-InCross-Platform Authentication with Google+ Sign-In
Cross-Platform Authentication with Google+ Sign-In
 
Bring Back the Fun to Testing Android Apps with Robolectric
Bring Back the Fun to Testing Android Apps with RobolectricBring Back the Fun to Testing Android Apps with Robolectric
Bring Back the Fun to Testing Android Apps with Robolectric
 
Do Androids Dream of Electric Sheep
Do Androids Dream of Electric SheepDo Androids Dream of Electric Sheep
Do Androids Dream of Electric Sheep
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 

Introduction to Android Wear

  • 2.
  • 3.
  • 4.
  • 5.
  • 8. • Launched automatically • Glanceable Design Principles
  • 9. • Launched automatically • Glanceable • Suggest and Demand Design Principles
  • 10. • Launched automatically • Glanceable • Suggest and Demand • Zero or low interaction Design Principles
  • 14. Simple Notifications Look, ma - no work required!
  • 15. Intent viewIntent = new Intent(context, DummyActivity.class);
 
 PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);
 Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .setContentIntent(viewPendingIntent)
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() Simple Notifications
  • 16. Can we do better?
  • 17.
  • 19. Intent viewIntent = new Intent(context, DummyActivity.class);
 
 PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);
 Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .setStyle(
 new NotificationCompat.BigPictureStyle()
 .bigPicture(BitmapFactory.decodeResource(context.getResources(), R.drawable.sanfrancisco))
 .setBigContentTitle("Flight AW123 is ready to board.")
 .setSummaryText("Please proceed to gate C 17 to board. Have a nice flight!"))
 .setContentIntent(viewPendingIntent)
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() BigPictureStyle
  • 20. Intent viewIntent = new Intent(context, DummyActivity.class);
 
 PendingIntent viewPendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);
 Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .setStyle(
 new NotificationCompat.BigPictureStyle()
 .bigPicture(BitmapFactory.decodeResource(context.getResources(), R.drawable.sanfrancisco))
 .setBigContentTitle("Flight AW123 is ready to board.")
 .setSummaryText("Please proceed to gate C 17 to board. Have a nice flight!"))
 .setContentIntent(viewPendingIntent)
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() BigPictureStyle Create BigPictureStyle
  • 22. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 .setContentTitle("Your seat")
 .setContentText("17A")
 .extend(new NotificationCompat.WearableExtender()
 .setBackground(BitmapFactory.decodeResource(context.getResources(), R.drawable.a380_seat)))
 .build()); sendNotification() Pages
  • 23. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 .setContentTitle("Your seat")
 .setContentText("17A")
 .extend(new NotificationCompat.WearableExtender()
 .setBackground(BitmapFactory.decodeResource(context.getResources(), R.drawable.a380_seat)))
 .build()); sendNotification() Pages Create page with title
  • 24. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 .setContentTitle("Your seat")
 .setContentText("17A")
 .extend(new NotificationCompat.WearableExtender()
 .setBackground(BitmapFactory.decodeResource(context.getResources(), R.drawable.a380_seat)))
 .build()); sendNotification() Pages Set background image
  • 27. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 // ... (set properties)
 .build()); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentIntent(viewPendingIntent)
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages))
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() Adding Pages to Notifications
  • 28. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 // ... (set properties)
 .build()); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentIntent(viewPendingIntent)
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages))
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() Adding Pages to Notifications Build pages
  • 29. ArrayList<Notification> pages = new ArrayList<Notification>();
 pages.add(new NotificationCompat.Builder(context)
 // ... (set properties)
 .build()); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentIntent(viewPendingIntent)
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages))
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification);
 sendNotification() Adding Pages to Notifications Add pages to notification
  • 31. // Feedback intent
 Intent replyIntent = new Intent(context, DummyActivity.class);
 PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);
 
 String replyLabel = context.getResources().getString(R.string.reply_label);
 String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 sendNotification() Voice Input
  • 32. // Feedback intent
 Intent replyIntent = new Intent(context, DummyActivity.class);
 PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);
 
 String replyLabel = context.getResources().getString(R.string.reply_label);
 String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 sendNotification() Voice Input Create pending intent
  • 33. // Feedback intent
 Intent replyIntent = new Intent(context, DummyActivity.class);
 PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);
 
 String replyLabel = context.getResources().getString(R.string.reply_label);
 String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 sendNotification() Voice Input Create RemoteInput with canned responses
  • 34. // Feedback intent
 Intent replyIntent = new Intent(context, DummyActivity.class);
 PendingIntent replyPendingIntent = PendingIntent.getActivity(context, 0, replyIntent, 0);
 
 String replyLabel = context.getResources().getString(R.string.reply_label);
 String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 sendNotification() Voice Input Create wearable action
  • 35. String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages)
 .addAction(replyAction))
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification); 
 sendNotification() Voice Input Create notification
  • 36. String[] cannedResponses = context.getResources().getStringArray(R.array.canned_responses);
 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
 .setLabel(replyLabel)
 .setChoices(cannedResponses)
 .build();
 
 NotificationCompat.Action replyAction =
 new NotificationCompat.Action.Builder( R.drawable.chatbubble_working, replyLabel, replyPendingIntent)
 .addRemoteInput(remoteInput)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages)
 .addAction(replyAction))
 .build();
 
 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
 notificationManager.notify(notificationId++, notification); 
 sendNotification() Voice Input Send notification
  • 37. Intent intent = getIntent();
 if (intent != null) { Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);
 if (remoteInputResults != null) {
 CharSequence utterance = remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY); 
 Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();
 } } ReceivingActivity.onCreate() Receiving Voice Input
  • 38. Intent intent = getIntent();
 if (intent != null) { Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);
 if (remoteInputResults != null) {
 CharSequence utterance = remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY); 
 Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();
 } } ReceivingActivity.onCreate() Receiving Voice Input Get remote input
  • 39. Intent intent = getIntent();
 if (intent != null) { Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);
 if (remoteInputResults != null) {
 CharSequence utterance = remoteInputResults.getCharSequence(Constants.EXTRA_VOICE_REPLY); 
 Toast.makeText(this, utterance, Toast.LENGTH_LONG).show();
 } } ReceivingActivity.onCreate() Receiving Voice Input Unpack voice reply
  • 41. Intent mapIntent = new Intent(Intent.ACTION_VIEW);
 Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));
 mapIntent.setData(geoUri);
 PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0); sendNotification() Actions
  • 42. Intent mapIntent = new Intent(Intent.ACTION_VIEW);
 Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));
 mapIntent.setData(geoUri);
 PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0);
 
 NotificationCompat.Action walkingDirectionsAction =
 new NotificationCompat.Action.Builder( R.drawable.ic_full_directions_walking, "Directions to gate", mapPendingIntent)
 .build(); sendNotification() Actions
  • 43. Intent mapIntent = new Intent(Intent.ACTION_VIEW);
 Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode("London Heathrow"));
 mapIntent.setData(geoUri);
 PendingIntent mapPendingIntent = PendingIntent.getActivity(context, 0, mapIntent, 0);
 
 NotificationCompat.Action walkingDirectionsAction =
 new NotificationCompat.Action.Builder( R.drawable.ic_full_directions_walking, "Directions to gate", mapPendingIntent)
 .build(); Notification notification = new NotificationCompat.Builder(context)
 .setSmallIcon(R.drawable.ic_launcher)
 .setSmallIcon(R.drawable.plane)
 .setContentTitle(String.format("Flight AW123 is ready to board", notificationId))
 .setContentText("Please proceed to gate C 17 to board. Have a nice flight!")
 .addAction(walkingDirectionsAction)
 .extend(new NotificationCompat.WearableExtender()
 .addPages(pages)
 .addAction(replyAction)
 .addAction(walkingDirectionsAction))
 .build();
 sendNotification() Actions
  • 45. Launching Wearable apps Using app-provided voice actions Using the start menu
  • 46. <application
 android:icon="@drawable/greenlinelogo"
 android:label="@string/app_name"
 android:theme="@android:style/Theme.DeviceDefault" >
 <activity
 android:name="de.peterfriese.weartravel.MainActivity"
 android:label="@string/app_name_voice" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 </application>
 AndroidManifest.xml Launching
  • 47. <application
 android:icon="@drawable/greenlinelogo"
 android:label="@string/app_name"
 android:theme="@android:style/Theme.DeviceDefault" >
 <activity
 android:name="de.peterfriese.weartravel.MainActivity"
 android:label="@string/app_name_voice" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 </application>
 AndroidManifest.xml Launching Label for voice action
  • 51. <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto">
 
 <android.support.wearable.view.CircledImageView
 android:id="@+id/image"
 android:alpha="0.5"
 android:layout_height="52dp"
 android:layout_marginLeft="16dp"
 android:layout_width="52dp"
 app:circle_border_color="#FFFFFFFF"
 app:circle_border_width="2dp"
 app:circle_color="#00000000"
 />
 
 <TextView
 android:id="@+id/text"
 android:alpha="0.5"
 android:fontFamily="sans-serif-condensed-light"
 android:gravity="center_vertical"
 android:layout_height="52dp"
 android:layout_marginLeft="72dp"
 checkin_listview_item.xml Layout - Item
  • 52. <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto">
 
 <android.support.wearable.view.CircledImageView
 android:id="@+id/image"
 android:alpha="0.5"
 android:layout_height="52dp"
 android:layout_marginLeft="16dp"
 android:layout_width="52dp"
 app:circle_border_color="#FFFFFFFF"
 app:circle_border_width="2dp"
 app:circle_color="#00000000"
 />
 
 <TextView
 android:id="@+id/text"
 android:alpha="0.5"
 android:fontFamily="sans-serif-condensed-light"
 android:gravity="center_vertical"
 android:layout_height="52dp"
 android:layout_marginLeft="72dp"
 android:layout_marginRight="16dp"
 android:layout_width="wrap_content"
 android:textColor="@color/white"
 android:textSize="14sp"
 />
 </merge> Layout - Item checkin_listview_item.xml
  • 53. private final class MyItemView extends FrameLayout implements WearableListView.OnCenterProximityListener {
 
 final CircledImageView image;
 final TextView text;
 
 public MyItemView(Context context) {
 super(context);
 View.inflate(context, R.layout.checkin_listview_item, this);
 image = (CircledImageView) findViewById(R.id.image);
 text = (TextView) findViewById(R.id.text);
 }
 
 @Override
 public void onCenterPosition(boolean b) {
 image.animate().scaleX(1f).scaleY(1f).alpha(1);
 text.animate().scaleX(1f).scaleY(1f).alpha(1);
 }
 
 @Override
 public void onNonCenterPosition(boolean b) {
 image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);
 CheckInActivity.java MyViewItem
  • 54. private final class MyItemView extends FrameLayout implements WearableListView.OnCenterProximityListener {
 
 final CircledImageView image;
 final TextView text;
 
 public MyItemView(Context context) {
 super(context);
 View.inflate(context, R.layout.checkin_listview_item, this);
 image = (CircledImageView) findViewById(R.id.image);
 text = (TextView) findViewById(R.id.text);
 }
 
 @Override
 public void onCenterPosition(boolean b) {
 image.animate().scaleX(1f).scaleY(1f).alpha(1);
 text.animate().scaleX(1f).scaleY(1f).alpha(1);
 }
 
 @Override
 public void onNonCenterPosition(boolean b) {
 image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);
 CheckInActivity.java MyViewItem
  • 55. private final class MyItemView extends FrameLayout implements WearableListView.OnCenterProximityListener {
 
 final CircledImageView image;
 final TextView text;
 
 public MyItemView(Context context) {
 super(context);
 View.inflate(context, R.layout.checkin_listview_item, this);
 image = (CircledImageView) findViewById(R.id.image);
 text = (TextView) findViewById(R.id.text);
 }
 
 @Override
 public void onCenterPosition(boolean b) {
 image.animate().scaleX(1f).scaleY(1f).alpha(1);
 text.animate().scaleX(1f).scaleY(1f).alpha(1);
 }
 
 @Override
 public void onNonCenterPosition(boolean b) {
 image.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);
 text.animate().scaleX(0.8f).scaleY(0.8f).alpha(0.6f);
 }
 } CheckInActivity.java MyViewItem
  • 56. public class CheckInActivity extends Activity implements WearableListView.ClickListener {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_checkin);
 
 MyListAdapter adapter = new MyListAdapter();
 
 WearableListView listView = (WearableListView) findViewById(R.id.checkin_list);
 listView.setAdapter(adapter);
 listView.setClickListener(CheckInActivity.this);
 }
 
 @Override
 public void onClick(WearableListView.ViewHolder viewHolder) {
 Toast.makeText(this, String.format("You selected item #%s", viewHolder.getPosition()), Toast.LENGTH_SHORT).show();
 }
 
 @Override
 public void onTopEmptyRegionClick() {
 CheckInActivity.java Activity
  • 57. public class CheckInActivity extends Activity implements WearableListView.ClickListener {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_checkin);
 
 MyListAdapter adapter = new MyListAdapter();
 
 WearableListView listView = (WearableListView) findViewById(R.id.checkin_list);
 listView.setAdapter(adapter);
 listView.setClickListener(CheckInActivity.this);
 }
 
 @Override
 public void onClick(WearableListView.ViewHolder viewHolder) {
 Toast.makeText(this, String.format("You selected item #%s", viewHolder.getPosition()), Toast.LENGTH_SHORT).show();
 }
 
 @Override
 public void onTopEmptyRegionClick() {
 Toast.makeText(this, "You tapped into the empty area above the list", Toast.LENGTH_SHORT).show();
 }
 CheckInActivity.java Activity
  • 59.
  • 61. • Square vs round Design Principles
  • 62. • Square vs round • Ambient mode / low-bit Design Principles
  • 63. • Square vs round • Ambient mode / low-bit • Legibility Design Principles 56° - Cloudy 56° - Cloudy
  • 65. • Start using a sample Developing Watch Faces
  • 66. • Start using a sample • Add a new wearable module Developing Watch Faces
  • 67. Architecture Wearable App Mobile App CanvasWatchFaceService ConfigActivity Engine ConfigActivityWearableListenerService
  • 70. @Override
 public void onCreate(SurfaceHolder holder) {
 super.onCreate(holder);
 
 setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
 .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
 .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
 .setShowSystemUiTime(false)
 .build());
 
 Resources resources = AnalogWatchFaceService.this.getResources();
 Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
 mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
 
 mHourPaint = new Paint();
 mHourPaint.setARGB(255, 200, 200, 200);
 mHourPaint.setStrokeWidth(5.f);
 mHourPaint.setAntiAlias(true);
 mHourPaint.setStrokeCap(Paint.Cap.ROUND); onCreate Lifecycle - initialise watch face elements
  • 71. @Override
 public void onCreate(SurfaceHolder holder) {
 super.onCreate(holder);
 
 setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
 .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
 .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
 .setShowSystemUiTime(false)
 .build());
 
 Resources resources = AnalogWatchFaceService.this.getResources();
 Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
 mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
 
 mHourPaint = new Paint();
 mHourPaint.setARGB(255, 200, 200, 200);
 mHourPaint.setStrokeWidth(5.f);
 mHourPaint.setAntiAlias(true);
 mHourPaint.setStrokeCap(Paint.Cap.ROUND); onCreate Lifecycle - initialise watch face elements Single-line peek card Do not show system time Show background briefly for interruptive cards
  • 72. @Override
 public void onCreate(SurfaceHolder holder) {
 super.onCreate(holder);
 
 setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
 .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
 .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
 .setShowSystemUiTime(false)
 .build());
 
 Resources resources = AnalogWatchFaceService.this.getResources();
 Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
 mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
 
 mHourPaint = new Paint();
 mHourPaint.setARGB(255, 200, 200, 200);
 mHourPaint.setStrokeWidth(5.f);
 mHourPaint.setAntiAlias(true);
 mHourPaint.setStrokeCap(Paint.Cap.ROUND); onCreate Lifecycle - initialise watch face elements Load background image
  • 73. @Override
 public void onCreate(SurfaceHolder holder) {
 super.onCreate(holder);
 
 setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
 .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
 .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
 .setShowSystemUiTime(false)
 .build());
 
 Resources resources = AnalogWatchFaceService.this.getResources();
 Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
 mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
 
 mHourPaint = new Paint();
 mHourPaint.setARGB(255, 200, 200, 200);
 mHourPaint.setStrokeWidth(5.f);
 mHourPaint.setAntiAlias(true);
 mHourPaint.setStrokeCap(Paint.Cap.ROUND); onCreate Lifecycle - initialise watch face elements Create styles for graphic objects
  • 74. @Override
 public void onDraw(Canvas canvas, Rect bounds) {
 mTime.setToNow();
 
 canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null); float centerX = width / 2f;
 float centerY = height / 2f;
 
 float innerTickRadius = centerX - 10;
 float outerTickRadius = centerX;
 for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
 float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
 canvas.drawLine(centerX + innerX, centerY + innerY,
 centerX + outerX, centerY + outerY, mTickPaint);
 }
 
 float secRot = mTime.second / 30f * (float) Math.PI;
 onDraw Lifecycle - draw the watch face
  • 75. @Override
 public void onDraw(Canvas canvas, Rect bounds) {
 mTime.setToNow();
 
 canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null); float centerX = width / 2f;
 float centerY = height / 2f;
 
 float innerTickRadius = centerX - 10;
 float outerTickRadius = centerX;
 for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
 float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
 canvas.drawLine(centerX + innerX, centerY + innerY,
 centerX + outerX, centerY + outerY, mTickPaint);
 }
 
 float secRot = mTime.second / 30f * (float) Math.PI;
 onDraw Lifecycle - draw the watch face Update time Draw background image
  • 76. @Override
 public void onDraw(Canvas canvas, Rect bounds) {
 mTime.setToNow();
 
 canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null); float centerX = width / 2f;
 float centerY = height / 2f;
 
 float innerTickRadius = centerX - 10;
 float outerTickRadius = centerX;
 for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
 float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
 canvas.drawLine(centerX + innerX, centerY + innerY,
 centerX + outerX, centerY + outerY, mTickPaint);
 }
 
 float secRot = mTime.second / 30f * (float) Math.PI;
 onDraw Lifecycle - draw the watch face Draw the ticks
  • 77. float centerX = width / 2f;
 float centerY = height / 2f;
 
 float innerTickRadius = centerX - 10;
 float outerTickRadius = centerX;
 for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
 float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
 canvas.drawLine(centerX + innerX, centerY + innerY,
 centerX + outerX, centerY + outerY, mTickPaint);
 }
 
 float secRot = mTime.second / 30f * (float) Math.PI;
 int minutes = mTime.minute;
 float minRot = minutes / 30f * (float) Math.PI;
 float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI;
 
 float secLength = centerX - 20;
 float minLength = centerX - 40;
 float hrLength = centerX - 80;
 if (!isInAmbientMode()) {
 float secX = (float) Math.sin(secRot) * secLength;
 float secY = (float) -Math.cos(secRot) * secLength;
 canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);
 }
 
 onDraw Lifecycle - draw the watch face Determine hands geometry
  • 78. float outerX = (float) Math.sin(tickRot) * outerTickRadius;
 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
 canvas.drawLine(centerX + innerX, centerY + innerY,
 centerX + outerX, centerY + outerY, mTickPaint);
 }
 
 float secRot = mTime.second / 30f * (float) Math.PI;
 int minutes = mTime.minute;
 float minRot = minutes / 30f * (float) Math.PI;
 float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI;
 
 float secLength = centerX - 20;
 float minLength = centerX - 40;
 float hrLength = centerX - 80;
 if (!isInAmbientMode()) {
 float secX = (float) Math.sin(secRot) * secLength;
 float secY = (float) -Math.cos(secRot) * secLength;
 canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);
 }
 
 float minX = (float) Math.sin(minRot) * minLength;
 float minY = (float) -Math.cos(minRot) * minLength;
 canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mMinutePaint);
 
 float hrX = (float) Math.sin(hrRot) * hrLength;
 float hrY = (float) -Math.cos(hrRot) * hrLength;
 canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHourPaint);
 } onDraw Lifecycle - draw the watch face Don’t draw seconds when in ambient mode Draw minutes hand Draw hours hand
  • 80. Demo