diff --git a/samples/wearable/.gitignore b/samples/wearable/.gitignore
new file mode 100644
index 000000000..a76265553
--- /dev/null
+++ b/samples/wearable/.gitignore
@@ -0,0 +1,42 @@
+# built application files
+*.apk
+*.ap_
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+out/
+src/common
+src/template
+_index.jd
+README.txt
+
+# Libraries used by the app
+# Can explicitly add if we want, but shouldn't do so blindly. Licenses, bloat, etc.
+/libs
+
+
+# Build stuff (auto-generated by android update project ...)
+ant.properties
+local.properties
+
+# Eclipse project files
+.classpath
+.project
+
+# idea project files
+.idea/
+.idea/.name
+*.iml
+*.ipr
+*.iws
+
+##Gradle-based build
+.gradle
+build/
+
diff --git a/samples/wearable/Notifications/Application/_index.html b/samples/wearable/Notifications/Application/_index.html
new file mode 100644
index 000000000..4bda0fa76
--- /dev/null
+++ b/samples/wearable/Notifications/Application/_index.html
@@ -0,0 +1,24 @@
+
This sample phone application provides a showcase of available notification
+styles and demonstrates various features of the Android Wear notifications
+API. Running the sample on your phone allows you to select between various
+notification styles and to see how these notifications are displayed, both in
+a phone's notification shade and on the wearable. The sample allows you to
+create the following types of notifications:
+
+- Basic notification
+- "Inbox style" notification: multiple lines of text
+- "Big picture style" notification: a full-screen background image for the
+card on the wearable
+- "Big text style" notification: a tall card that is collapsed and can be
+expanded with a tap
+- "Big action style" notification: tapping anywhere on the card triggers the
+notification content intent
+- Notification with multiple pages: swipe horizontally to view the second
+page
+- Bundled Notifications: a stack of cards that can be individually
+expanded
+
+This sample also allows you to toggle other attributes for each of these
+notification types, including whether a content intent or action are included,
+and whether the notification is marked as "local only," indicating that it
+should not be bridged between devices.
diff --git a/samples/wearable/Notifications/Application/build.gradle b/samples/wearable/Notifications/Application/build.gradle
new file mode 100644
index 000000000..5eb4f8b49
--- /dev/null
+++ b/samples/wearable/Notifications/Application/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'android'
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "19.1"
+
+ defaultConfig {
+ minSdkVersion 18
+ targetSdkVersion 19
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ runProguard false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+
+ aaptOptions {
+ noCompress 'apk'
+ }
+}
+
+dependencies {
+ compile "com.android.support:support-v4:20.0.+"
+ wearApp project(':Wearable')
+}
\ No newline at end of file
diff --git a/samples/wearable/Notifications/Application/proguard-rules.txt b/samples/wearable/Notifications/Application/proguard-rules.txt
new file mode 100644
index 000000000..08e5bdc8d
--- /dev/null
+++ b/samples/wearable/Notifications/Application/proguard-rules.txt
@@ -0,0 +1,22 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+-dontwarn android.support.wearable.view.DelayedConfirmationView
+-dontwarn android.support.wearable.view.CircledImageView
diff --git a/samples/wearable/Notifications/Application/src/main/AndroidManifest.xml b/samples/wearable/Notifications/Application/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..a5e530e6a
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPreset.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPreset.java
new file mode 100644
index 000000000..86fe67e0e
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPreset.java
@@ -0,0 +1,17 @@
+package com.example.android.support.wearable.notifications;
+
+import android.content.Context;
+import android.support.v4.app.NotificationCompat;
+
+/**
+ * Base class for notification actions presets.
+ */
+public abstract class ActionsPreset extends NamedPreset {
+ public ActionsPreset(int nameResId) {
+ super(nameResId);
+ }
+
+ /** Apply the priority to a notification builder */
+ public abstract void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions);
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPresets.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPresets.java
new file mode 100644
index 000000000..ebac6c086
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/ActionsPresets.java
@@ -0,0 +1,142 @@
+package com.example.android.support.wearable.notifications;
+
+import android.content.Context;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.RemoteInput;
+
+/**
+ * Collection of notification actions presets.
+ */
+public class ActionsPresets {
+ public static final ActionsPreset NO_ACTIONS_PRESET = new NoActionsPreset();
+ public static final ActionsPreset SINGLE_ACTION_PRESET = new SingleActionPreset();
+
+ public static final ActionsPreset[] PRESETS = new ActionsPreset[] {
+ NO_ACTIONS_PRESET,
+ SINGLE_ACTION_PRESET,
+ new ReplyActionPreset(),
+ new ReplyWithChoicesActionPreset(),
+ new DifferentActionsOnPhoneAndWearable(),
+ new LongTitleActionPreset()
+ };
+
+ private static class NoActionsPreset extends ActionsPreset {
+ public NoActionsPreset() {
+ super(R.string.no_actions);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ }
+ }
+
+ private static class SingleActionPreset extends ActionsPreset {
+ public SingleActionPreset() {
+ super(R.string.single_action);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ builder.addAction(R.drawable.ic_full_action,
+ context.getString(R.string.example_action),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.example_action_clicked))
+ .build();
+ }
+ }
+
+ private static class LongTitleActionPreset extends ActionsPreset {
+ public LongTitleActionPreset() {
+ super(R.string.long_title_action);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ builder.addAction(R.drawable.ic_full_action,
+ context.getString(R.string.example_action_long_title),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.example_action_clicked))
+ .build();
+ }
+ }
+
+ private static class ReplyActionPreset extends ActionsPreset {
+ public ReplyActionPreset() {
+ super(R.string.reply_action);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ RemoteInput remoteInput = new RemoteInput.Builder(NotificationUtil.EXTRA_REPLY)
+ .setLabel(context.getString(R.string.example_reply_label))
+ .build();
+ NotificationCompat.Action action = new NotificationCompat.Action.Builder(
+ R.drawable.ic_full_reply,
+ context.getString(R.string.example_reply_action),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.example_reply_action_clicked))
+ .addRemoteInput(remoteInput)
+ .build();
+ builder.addAction(action);
+ }
+ }
+
+ private static class ReplyWithChoicesActionPreset extends ActionsPreset {
+ public ReplyWithChoicesActionPreset() {
+ super(R.string.reply_action_with_choices);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ RemoteInput remoteInput = new RemoteInput.Builder(NotificationUtil.EXTRA_REPLY)
+ .setLabel(context.getString(R.string.example_reply_answer_label))
+ .setChoices(new String[] { context.getString(R.string.yes),
+ context.getString(R.string.no), context.getString(R.string.maybe) })
+ .build();
+ NotificationCompat.Action action = new NotificationCompat.Action.Builder(
+ R.drawable.ic_full_reply,
+ context.getString(R.string.example_reply_action),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.example_reply_action_clicked))
+ .addRemoteInput(remoteInput)
+ .build();
+ wearableOptions.addAction(action);
+ }
+ }
+
+ private static class DifferentActionsOnPhoneAndWearable extends ActionsPreset {
+ public DifferentActionsOnPhoneAndWearable() {
+ super(R.string.different_actions_on_phone_and_wearable);
+ }
+
+ @Override
+ public void apply(Context context, NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ NotificationCompat.Action phoneAction = new NotificationCompat.Action.Builder(
+ R.drawable.ic_full_action,
+ context.getString(R.string.phone_action),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.phone_action_clicked))
+ .build();
+ builder.addAction(phoneAction);
+
+ RemoteInput remoteInput = new RemoteInput.Builder(NotificationUtil.EXTRA_REPLY)
+ .setLabel(context.getString(R.string.example_reply_label))
+ .build();
+
+ NotificationCompat.Action wearableAction = new NotificationCompat.Action.Builder(
+ R.drawable.ic_full_reply,
+ context.getString(R.string.wearable_action),
+ NotificationUtil.getExamplePendingIntent(context,
+ R.string.wearable_action_clicked))
+ .addRemoteInput(remoteInput)
+ .build();
+ wearableOptions.addAction(wearableAction);
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/BackgroundPickers.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/BackgroundPickers.java
new file mode 100644
index 000000000..58b3dfedc
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/BackgroundPickers.java
@@ -0,0 +1,124 @@
+package com.example.android.support.wearable.notifications;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the background image pickers.
+ */
+public class BackgroundPickers {
+
+ public interface OnBackgroundPickersChangedListener {
+ public void onBackgroundPickersChanged(BackgroundPickers pickers);
+ }
+
+ private final ViewGroup mContainer;
+ private final OnPickedListener mOnPickedListener;
+ private final List mPickers;
+ private final OnBackgroundPickersChangedListener listener;
+
+ public BackgroundPickers(ViewGroup container, OnBackgroundPickersChangedListener listener) {
+ this.mContainer = container;
+ this.mOnPickedListener = new OnPickedListener();
+ this.mPickers = new ArrayList();
+ this.listener = listener;
+ }
+
+ /**
+ * Generates the pickers as necessary.
+ */
+ public void generatePickers(int count) {
+ // Clear existing containers.
+ clear();
+
+ // Fill in new pickers.
+ LayoutInflater inflater = LayoutInflater.from(mContainer.getContext());
+ Resources res = mContainer.getResources();
+ for (int i = 0; i < count; i++) {
+ View picker = inflater.inflate(R.layout.background_picker, mContainer, false);
+ TextView label = (TextView) picker.findViewById(R.id.bg_picker_label);
+ label.setText(String.format(res.getString(R.string.bg_picker_label), i+1));
+ ViewGroup pickerBox = (ViewGroup) picker.findViewById(R.id.bg_picker_container);
+ mPickers.add(pickerBox);
+ for (int j = 0; j < pickerBox.getChildCount(); j++) {
+ ImageView img = (ImageView) pickerBox.getChildAt(j);
+ img.setOnClickListener(mOnPickedListener);
+ }
+ mContainer.addView(picker);
+ }
+ }
+
+ /**
+ * Returns the background resource for the picker at the given index.
+ * @param position Index of the background picker.
+ * @return Id of the background image resource. null if no image is picked.
+ */
+ public Integer getRes(int position) {
+ String tag = (String) mPickers.get(position).getTag();
+ if (tag == null) {
+ return null;
+ }
+
+ Context context = mContainer.getContext();
+ return context.getResources().getIdentifier(tag, "drawable", context.getPackageName());
+ }
+
+ /**
+ * Returns the all the background resources for the pickers managed by this object. Returns null
+ * if no pickers exist.
+ */
+ public Integer[] getRes() {
+ if (mPickers.size() == 0) {
+ return null;
+ }
+
+ Integer[] res = new Integer[mPickers.size()];
+ for (int i = 0; i < mPickers.size(); i++) {
+ res[i] = getRes(i);
+ }
+ return res;
+ }
+
+ /**
+ * Clears the pickers.
+ */
+ public void clear() {
+ mContainer.removeAllViews();
+ mPickers.clear();
+ }
+
+ public int getCount() {
+ return mPickers.size();
+ }
+
+ private class OnPickedListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View view) {
+ ImageView pickedView = (ImageView) view;
+ ViewGroup pickerBox = (ViewGroup) view.getParent();
+
+ // Clear old selection.
+ for (int i = 0; i < pickerBox.getChildCount(); i++) {
+ ImageView childView = (ImageView) pickerBox.getChildAt(i);
+ childView.setBackgroundResource(R.drawable.unselected_background);
+ }
+
+ // Set new selection.
+ pickedView.setBackgroundResource(R.drawable.selected_background);
+ pickerBox.setTag(pickedView.getTag());
+
+ if (listener != null) {
+ listener.onBackgroundPickersChanged(BackgroundPickers.this);
+ }
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
new file mode 100644
index 000000000..a7474aa7a
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
@@ -0,0 +1,336 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v4.app.NotificationManagerCompat;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import java.util.Arrays;
+
+/**
+ * Main activity which posts a notification when resumed, and allows customization
+ * of that notification via controls.
+ */
+public class MainActivity extends Activity implements Handler.Callback {
+ private static final int MSG_POST_NOTIFICATIONS = 0;
+ private static final long POST_NOTIFICATIONS_DELAY_MS = 200;
+
+ private Handler mHandler;
+ private Spinner mPresetSpinner;
+ private EditText mTitleEditText;
+ private EditText mTextEditText;
+ private TextWatcher mTextChangedListener;
+ private Spinner mPrioritySpinner;
+ private Spinner mActionsSpinner;
+ private CheckBox mIncludeLargeIconCheckbox;
+ private CheckBox mLocalOnlyCheckbox;
+ private CheckBox mIncludeContentIntentCheckbox;
+ private CheckBox mVibrateCheckbox;
+ private BackgroundPickers mBackgroundPickers;
+ private int postedNotificationCount = 0;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mHandler = new Handler(this);
+ mTextChangedListener = new UpdateNotificationsOnTextChangeListener();
+
+ initPresetSpinner();
+ initTitleEditText();
+ initTextEditText();
+ initPrioritySpinner();
+ initActionsSpinner();
+ initIncludeLargeIconCheckbox();
+ initLocalOnlyCheckbox();
+ initIncludeContentIntentCheckbox();
+ initVibrateCheckbox();
+ initBackgroundPickers();
+
+ NotificationPreset preset = NotificationPresets.PRESETS[
+ mPresetSpinner.getSelectedItemPosition()];
+ updateTextEditors(preset);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateNotifications(false /* cancelExisting */);
+ }
+
+ private void initPresetSpinner() {
+ mPresetSpinner = (Spinner) findViewById(R.id.preset_spinner);
+ mPresetSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
+ NotificationPresets.PRESETS));
+ mPresetSpinner.post(new Runnable() {
+ @Override
+ public void run() {
+ mPresetSpinner.setOnItemSelectedListener(new PresetSpinnerListener());
+ }
+ });
+ }
+
+ private void initTitleEditText() {
+ mTitleEditText = (EditText) findViewById(R.id.title_editor);
+ }
+
+ private void initTextEditText() {
+ mTextEditText = (EditText) findViewById(R.id.text_editor);
+ }
+
+ private void initPrioritySpinner() {
+ mPrioritySpinner = (Spinner) findViewById(R.id.priority_spinner);
+ mPrioritySpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
+ PriorityPresets.PRESETS));
+ mPrioritySpinner.setSelection(Arrays.asList(PriorityPresets.PRESETS)
+ .indexOf(PriorityPresets.DEFAULT));
+ mPrioritySpinner.post(new Runnable() {
+ @Override
+ public void run() {
+ mPrioritySpinner.setOnItemSelectedListener(
+ new UpdateNotificationsOnItemSelectedListener(true /* cancelExisting */));
+ }
+ });
+ }
+
+ private void initActionsSpinner() {
+ mActionsSpinner = (Spinner) findViewById(R.id.actions_spinner);
+ mActionsSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
+ ActionsPresets.PRESETS));
+ mActionsSpinner.post(new Runnable() {
+ @Override
+ public void run() {
+ mActionsSpinner.setOnItemSelectedListener(
+ new UpdateNotificationsOnItemSelectedListener(false /* cancelExisting */));
+ }
+ });
+ }
+
+ private void initIncludeLargeIconCheckbox() {
+ mIncludeLargeIconCheckbox = (CheckBox) findViewById(R.id.include_large_icon_checkbox);
+ mIncludeLargeIconCheckbox.setOnCheckedChangeListener(
+ new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
+ }
+
+ private void initLocalOnlyCheckbox() {
+ mLocalOnlyCheckbox = (CheckBox) findViewById(R.id.local_only_checkbox);
+ mLocalOnlyCheckbox.setOnCheckedChangeListener(
+ new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
+ }
+
+ private void initIncludeContentIntentCheckbox() {
+ mIncludeContentIntentCheckbox = (CheckBox) findViewById(
+ R.id.include_content_intent_checkbox);
+ mIncludeContentIntentCheckbox.setOnCheckedChangeListener(
+ new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
+ }
+
+ private void initVibrateCheckbox() {
+ mVibrateCheckbox = (CheckBox) findViewById(R.id.vibrate_checkbox);
+ mVibrateCheckbox.setOnCheckedChangeListener(
+ new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
+ }
+
+ private void initBackgroundPickers() {
+ mBackgroundPickers = new BackgroundPickers(
+ (ViewGroup) findViewById(R.id.background_pickers),
+ new BackgroundPickerListener());
+ }
+
+ private void updateTextEditors(NotificationPreset preset) {
+ if (preset == NotificationPresets.BASIC) {
+ findViewById(R.id.title_edit_field).setVisibility(View.VISIBLE);
+ mTitleEditText.setText(getString(preset.titleResId));
+ mTitleEditText.addTextChangedListener(mTextChangedListener);
+ findViewById(R.id.text_edit_field).setVisibility(View.VISIBLE);
+ mTextEditText.setText(getString(preset.textResId));
+ mTextEditText.addTextChangedListener(mTextChangedListener);
+ } else {
+ findViewById(R.id.title_edit_field).setVisibility(View.GONE);
+ mTitleEditText.removeTextChangedListener(mTextChangedListener);
+ findViewById(R.id.text_edit_field).setVisibility(View.GONE);
+ mTextEditText.removeTextChangedListener(mTextChangedListener);
+ }
+ }
+
+ /**
+ * Begin to re-post the sample notification(s).
+ */
+ private void updateNotifications(boolean cancelExisting) {
+ // Disable messages to skip notification deleted messages during cancel.
+ sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_DISABLE_MESSAGES)
+ .setClass(this, NotificationIntentReceiver.class));
+
+ if (cancelExisting) {
+ // Cancel all existing notifications to trigger fresh-posting behavior: For example,
+ // switching from HIGH to LOW priority does not cause a reordering in Notification Shade.
+ NotificationManagerCompat.from(this).cancelAll();
+ postedNotificationCount = 0;
+
+ // Post the updated notifications on a delay to avoid a cancel+post race condition
+ // with notification manager.
+ mHandler.removeMessages(MSG_POST_NOTIFICATIONS);
+ mHandler.sendEmptyMessageDelayed(MSG_POST_NOTIFICATIONS, POST_NOTIFICATIONS_DELAY_MS);
+ } else {
+ postNotifications();
+ }
+ }
+
+ /**
+ * Post the sample notification(s) using current options.
+ */
+ private void postNotifications() {
+ sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_ENABLE_MESSAGES)
+ .setClass(this, NotificationIntentReceiver.class));
+
+ NotificationPreset preset = NotificationPresets.PRESETS[
+ mPresetSpinner.getSelectedItemPosition()];
+ CharSequence titlePreset = mTitleEditText.getText();
+ CharSequence textPreset = mTextEditText.getText();
+ PriorityPreset priorityPreset = PriorityPresets.PRESETS[
+ mPrioritySpinner.getSelectedItemPosition()];
+ ActionsPreset actionsPreset = ActionsPresets.PRESETS[
+ mActionsSpinner.getSelectedItemPosition()];
+ if (preset.actionsRequired() && actionsPreset == ActionsPresets.NO_ACTIONS_PRESET) {
+ // If actions are required, but the no-actions preset was selected, change presets.
+ actionsPreset = ActionsPresets.SINGLE_ACTION_PRESET;
+ mActionsSpinner.setSelection(Arrays.asList(ActionsPresets.PRESETS).indexOf(
+ actionsPreset), true);
+ }
+ NotificationPreset.BuildOptions options = new NotificationPreset.BuildOptions(
+ titlePreset,
+ textPreset,
+ priorityPreset,
+ actionsPreset,
+ mIncludeLargeIconCheckbox.isChecked(),
+ mLocalOnlyCheckbox.isChecked(),
+ mIncludeContentIntentCheckbox.isChecked(),
+ mVibrateCheckbox.isChecked(),
+ mBackgroundPickers.getRes());
+ Notification[] notifications = preset.buildNotifications(this, options);
+
+ // Post new notifications
+ for (int i = 0; i < notifications.length; i++) {
+ NotificationManagerCompat.from(this).notify(i, notifications[i]);
+ }
+ // Cancel any that are beyond the current count.
+ for (int i = notifications.length; i < postedNotificationCount; i++) {
+ NotificationManagerCompat.from(this).cancel(i);
+ }
+ postedNotificationCount = notifications.length;
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_POST_NOTIFICATIONS:
+ postNotifications();
+ return true;
+ }
+ return false;
+ }
+
+ private class PresetSpinnerListener implements AdapterView.OnItemSelectedListener {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ NotificationPreset preset = NotificationPresets.PRESETS[position];
+ mBackgroundPickers.generatePickers(preset.countBackgroundPickersRequired());
+ updateTextEditors(preset);
+ updateNotifications(false /* cancelExisting */);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+ }
+ }
+
+ private class UpdateNotificationsOnTextChangeListener implements TextWatcher {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateNotifications(false /* cancelExisting */);
+ }
+ }
+
+ private class UpdateNotificationsOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+ private final boolean mCancelExisting;
+
+ public UpdateNotificationsOnItemSelectedListener(boolean cancelExisting) {
+ mCancelExisting = cancelExisting;
+ }
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ updateNotifications(mCancelExisting);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+ }
+ }
+
+ private class UpdateNotificationsOnCheckedChangeListener
+ implements CompoundButton.OnCheckedChangeListener {
+ private final boolean mCancelExisting;
+
+ public UpdateNotificationsOnCheckedChangeListener(boolean cancelExisting) {
+ mCancelExisting = cancelExisting;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ updateNotifications(mCancelExisting);
+ }
+ }
+
+ private class BackgroundPickerListener
+ implements BackgroundPickers.OnBackgroundPickersChangedListener {
+ @Override
+ public void onBackgroundPickersChanged(BackgroundPickers pickers) {
+ updateNotifications(false /* cancelExisting */);
+ }
+ }
+
+ private class NamedPresetSpinnerArrayAdapter extends ArrayAdapter {
+ public NamedPresetSpinnerArrayAdapter(Context context, NamedPreset[] presets) {
+ super(context, R.layout.simple_spinner_item, presets);
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ TextView view = (TextView) super.getDropDownView(position, convertView, parent);
+ view.setText(getString(getItem(position).nameResId));
+ return view;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view = (TextView) getLayoutInflater().inflate(
+ android.R.layout.simple_spinner_item, parent, false);
+ view.setText(getString(getItem(position).nameResId));
+ return view;
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NamedPreset.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NamedPreset.java
new file mode 100644
index 000000000..c68251fb3
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NamedPreset.java
@@ -0,0 +1,12 @@
+package com.example.android.support.wearable.notifications;
+
+/**
+ * Base class for presets that have a simple name to display.
+ */
+public abstract class NamedPreset {
+ public final int nameResId;
+
+ public NamedPreset(int nameResId) {
+ this.nameResId = nameResId;
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationIntentReceiver.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationIntentReceiver.java
new file mode 100644
index 000000000..08d720855
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationIntentReceiver.java
@@ -0,0 +1,44 @@
+package com.example.android.support.wearable.notifications;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.RemoteInput;
+import android.widget.Toast;
+
+/**
+ * Broadcast receiver to post toast messages in response to notification intents firing.
+ */
+public class NotificationIntentReceiver extends BroadcastReceiver {
+ public static final String ACTION_EXAMPLE =
+ "com.example.android.support.wearable.notifications.ACTION_EXAMPLE";
+ public static final String ACTION_ENABLE_MESSAGES =
+ "com.example.android.support.wearable.notifications.ACTION_ENABLE_MESSAGES";
+ public static final String ACTION_DISABLE_MESSAGES =
+ "com.example.android.support.wearable.notifications.ACTION_DISABLE_MESSAGES";
+
+ private boolean mEnableMessages = true;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(ACTION_EXAMPLE)) {
+ if (mEnableMessages) {
+ String message = intent.getStringExtra(NotificationUtil.EXTRA_MESSAGE);
+ Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);
+ CharSequence replyMessage = null;
+ if (remoteInputResults != null) {
+ replyMessage = remoteInputResults.getCharSequence(NotificationUtil.EXTRA_REPLY);
+ }
+ if (replyMessage != null) {
+ message = message + ": \"" + replyMessage + "\"";
+ }
+ Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+ }
+ } else if (intent.getAction().equals(ACTION_ENABLE_MESSAGES)) {
+ mEnableMessages = true;
+ } else if (intent.getAction().equals(ACTION_DISABLE_MESSAGES)) {
+ mEnableMessages = false;
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java
new file mode 100644
index 000000000..a28949475
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java
@@ -0,0 +1,58 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.content.Context;
+
+/**
+ * Base class for notification preset generators.
+ */
+public abstract class NotificationPreset extends NamedPreset {
+ public final int titleResId;
+ public final int textResId;
+
+ public NotificationPreset(int nameResId, int titleResId, int textResId) {
+ super(nameResId);
+ this.titleResId = titleResId;
+ this.textResId = textResId;
+ }
+
+ public static class BuildOptions {
+ public final CharSequence titlePreset;
+ public final CharSequence textPreset;
+ public final PriorityPreset priorityPreset;
+ public final ActionsPreset actionsPreset;
+ public final boolean includeLargeIcon;
+ public final boolean isLocalOnly;
+ public final boolean hasContentIntent;
+ public final boolean vibrate;
+ public final Integer[] backgroundIds;
+
+ public BuildOptions(CharSequence titlePreset, CharSequence textPreset,
+ PriorityPreset priorityPreset, ActionsPreset actionsPreset,
+ boolean includeLargeIcon, boolean isLocalOnly, boolean hasContentIntent,
+ boolean vibrate, Integer[] backgroundIds) {
+ this.titlePreset = titlePreset;
+ this.textPreset = textPreset;
+ this.priorityPreset = priorityPreset;
+ this.actionsPreset = actionsPreset;
+ this.includeLargeIcon = includeLargeIcon;
+ this.isLocalOnly = isLocalOnly;
+ this.hasContentIntent = hasContentIntent;
+ this.vibrate = vibrate;
+ this.backgroundIds = backgroundIds;
+ }
+ }
+
+ /** Build a notification with this preset and the provided options */
+ public abstract Notification[] buildNotifications(Context context, BuildOptions options);
+
+ /** Whether actions are required to use this preset. */
+ public boolean actionsRequired() {
+ return false;
+ }
+
+ /** Number of background pickers required */
+ public int countBackgroundPickersRequired() {
+ return 0;
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java
new file mode 100644
index 000000000..f175145bf
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java
@@ -0,0 +1,463 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.support.v4.app.NotificationCompat;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StrikethroughSpan;
+import android.text.style.StyleSpan;
+import android.text.style.SubscriptSpan;
+import android.text.style.SuperscriptSpan;
+import android.text.style.TypefaceSpan;
+import android.text.style.UnderlineSpan;
+import android.view.Gravity;
+
+/**
+ * Collection of notification builder presets.
+ */
+public class NotificationPresets {
+ private static final String EXAMPLE_GROUP_KEY = "example";
+
+ public static final NotificationPreset BASIC = new BasicNotificationPreset();
+ public static final NotificationPreset STYLIZED_TEXT = new StylizedTextNotificationPreset();
+ public static final NotificationPreset INBOX = new InboxNotificationPreset();
+ public static final NotificationPreset BIG_PICTURE = new BigPictureNotificationPreset();
+ public static final NotificationPreset BIG_TEXT = new BigTextNotificationPreset();
+ public static final NotificationPreset BOTTOM_ALIGNED = new BottomAlignedNotificationPreset();
+ public static final NotificationPreset GRAVITY = new GravityNotificationPreset();
+ public static final NotificationPreset CONTENT_ACTION = new ContentActionNotificationPreset();
+ public static final NotificationPreset CONTENT_ICON = new ContentIconNotificationPreset();
+ public static final NotificationPreset MULTIPLE_PAGE = new MultiplePageNotificationPreset();
+ public static final NotificationPreset BUNDLE = new NotificationBundlePreset();
+
+ public static final NotificationPreset[] PRESETS = new NotificationPreset[] {
+ BASIC,
+ STYLIZED_TEXT,
+ INBOX,
+ BIG_PICTURE,
+ BIG_TEXT,
+ BOTTOM_ALIGNED,
+ GRAVITY,
+ CONTENT_ACTION,
+ CONTENT_ICON,
+ MULTIPLE_PAGE,
+ BUNDLE
+ };
+
+ private static NotificationCompat.Builder applyBasicOptions(Context context,
+ NotificationCompat.Builder builder, NotificationCompat.WearableExtender wearableOptions,
+ NotificationPreset.BuildOptions options) {
+ builder.setContentTitle(options.titlePreset)
+ .setContentText(options.textPreset)
+ .setSmallIcon(R.mipmap.ic_launcher)
+ .setDeleteIntent(NotificationUtil.getExamplePendingIntent(
+ context, R.string.example_notification_deleted));
+ options.actionsPreset.apply(context, builder, wearableOptions);
+ options.priorityPreset.apply(builder, wearableOptions);
+ if (options.includeLargeIcon) {
+ builder.setLargeIcon(BitmapFactory.decodeResource(
+ context.getResources(), R.drawable.example_large_icon));
+ }
+ if (options.isLocalOnly) {
+ builder.setLocalOnly(true);
+ }
+ if (options.hasContentIntent) {
+ builder.setContentIntent(NotificationUtil.getExamplePendingIntent(context,
+ R.string.content_intent_clicked));
+ }
+ if (options.vibrate) {
+ builder.setVibrate(new long[] {0, 100, 50, 100} );
+ }
+ return builder;
+ }
+
+ private static class BasicNotificationPreset extends NotificationPreset {
+ public BasicNotificationPreset() {
+ super(R.string.basic_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class StylizedTextNotificationPreset extends NotificationPreset {
+ public StylizedTextNotificationPreset() {
+ super(R.string.stylized_text_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle();
+
+ SpannableStringBuilder title = new SpannableStringBuilder();
+ appendStyled(title, "Stylized", new StyleSpan(Typeface.BOLD_ITALIC));
+ title.append(" title");
+ SpannableStringBuilder text = new SpannableStringBuilder("Stylized text: ");
+ appendStyled(text, "C", new ForegroundColorSpan(Color.RED));
+ appendStyled(text, "O", new ForegroundColorSpan(Color.GREEN));
+ appendStyled(text, "L", new ForegroundColorSpan(Color.BLUE));
+ appendStyled(text, "O", new ForegroundColorSpan(Color.YELLOW));
+ appendStyled(text, "R", new ForegroundColorSpan(Color.MAGENTA));
+ appendStyled(text, "S", new ForegroundColorSpan(Color.CYAN));
+ text.append("; ");
+ appendStyled(text, "1.25x size", new RelativeSizeSpan(1.25f));
+ text.append("; ");
+ appendStyled(text, "0.75x size", new RelativeSizeSpan(0.75f));
+ text.append("; ");
+ appendStyled(text, "underline", new UnderlineSpan());
+ text.append("; ");
+ appendStyled(text, "strikethrough", new StrikethroughSpan());
+ text.append("; ");
+ appendStyled(text, "bold", new StyleSpan(Typeface.BOLD));
+ text.append("; ");
+ appendStyled(text, "italic", new StyleSpan(Typeface.ITALIC));
+ text.append("; ");
+ appendStyled(text, "sans-serif-thin", new TypefaceSpan("sans-serif-thin"));
+ text.append("; ");
+ appendStyled(text, "monospace", new TypefaceSpan("monospace"));
+ text.append("; ");
+ appendStyled(text, "sub", new SubscriptSpan());
+ text.append("script");
+ appendStyled(text, "super", new SuperscriptSpan());
+
+ style.setBigContentTitle(title);
+ style.bigText(text);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+ .setStyle(style);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+
+ private void appendStyled(SpannableStringBuilder builder, String str, Object... spans) {
+ builder.append(str);
+ for (Object span : spans) {
+ builder.setSpan(span, builder.length() - str.length(), builder.length(), 0);
+ }
+ }
+ }
+
+ private static class InboxNotificationPreset extends NotificationPreset {
+ public InboxNotificationPreset() {
+ super(R.string.inbox_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
+ style.addLine(context.getString(R.string.inbox_style_example_line1));
+ style.addLine(context.getString(R.string.inbox_style_example_line2));
+ style.addLine(context.getString(R.string.inbox_style_example_line3));
+ style.setBigContentTitle(context.getString(R.string.inbox_style_example_title));
+ style.setSummaryText(context.getString(R.string.inbox_style_example_summary_text));
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+ .setStyle(style);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class BigPictureNotificationPreset extends NotificationPreset {
+ public BigPictureNotificationPreset() {
+ super(R.string.big_picture_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
+ style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
+ R.drawable.example_big_picture));
+ style.setBigContentTitle(context.getString(R.string.big_picture_style_example_title));
+ style.setSummaryText(context.getString(
+ R.string.big_picture_style_example_summary_text));
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+ .setStyle(style);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class BigTextNotificationPreset extends NotificationPreset {
+ public BigTextNotificationPreset() {
+ super(R.string.big_text_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle();
+ style.bigText(context.getString(R.string.big_text_example_big_text));
+ style.setBigContentTitle(context.getString(R.string.big_text_example_title));
+ style.setSummaryText(context.getString(R.string.big_text_example_summary_text));
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+ .setStyle(style);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class BottomAlignedNotificationPreset extends NotificationPreset {
+ public BottomAlignedNotificationPreset() {
+ super(R.string.bottom_aligned_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+
+ NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context);
+ secondPageBuilder.setContentTitle(
+ context.getString(R.string.second_page_content_title));
+ secondPageBuilder.setContentText(context.getString(R.string.big_text_example_big_text));
+ secondPageBuilder.extend(new NotificationCompat.WearableExtender()
+ .setStartScrollBottom(true));
+
+ wearableOptions.addPage(secondPageBuilder.build());
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class GravityNotificationPreset extends NotificationPreset {
+ public GravityNotificationPreset() {
+ super(R.string.gravity_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, builder, wearableOptions, options);
+
+ NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context)
+ .setContentTitle(options.titlePreset)
+ .setContentText(options.textPreset)
+ .extend(new NotificationCompat.WearableExtender()
+ .setGravity(Gravity.CENTER_VERTICAL));
+ wearableOptions.addPage(secondPageBuilder.build());
+
+ NotificationCompat.Builder thirdPageBuilder = new NotificationCompat.Builder(context)
+ .setContentTitle(options.titlePreset)
+ .setContentText(options.textPreset)
+ .extend(new NotificationCompat.WearableExtender()
+ .setGravity(Gravity.TOP));
+ wearableOptions.addPage(thirdPageBuilder.build());
+
+ wearableOptions.setGravity(Gravity.BOTTOM);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class ContentActionNotificationPreset extends NotificationPreset {
+ public ContentActionNotificationPreset() {
+ super(R.string.content_action_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ Notification secondPage = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.second_page_content_title))
+ .setContentText(context.getString(R.string.second_page_content_text))
+ .extend(new NotificationCompat.WearableExtender()
+ .setContentAction(1))
+ .build();
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationCompat.Action action = new NotificationCompat.Action.Builder(
+ R.drawable.ic_result_open, null, NotificationUtil.getExamplePendingIntent(
+ context, R.string.example_content_action_clicked)).build();
+ NotificationCompat.Action action2 = new NotificationCompat.Action.Builder(
+ R.drawable.ic_result_open, null, NotificationUtil.getExamplePendingIntent(
+ context, R.string.example_content_action2_clicked)).build();
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender()
+ .addAction(action)
+ .addAction(action2)
+ .addPage(secondPage)
+ .setContentAction(0)
+ .setHintHideIcon(true);
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+
+ @Override
+ public boolean actionsRequired() {
+ return true;
+ }
+ }
+
+ private static class ContentIconNotificationPreset extends NotificationPreset {
+ public ContentIconNotificationPreset() {
+ super(R.string.content_icon_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ Notification secondPage = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.second_page_content_title))
+ .setContentText(context.getString(R.string.second_page_content_text))
+ .extend(new NotificationCompat.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_small)
+ .setContentIconGravity(Gravity.START))
+ .build();
+
+ Notification thirdPage = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.third_page_content_title))
+ .setContentText(context.getString(R.string.third_page_content_text))
+ .extend(new NotificationCompat.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_large))
+ .build();
+
+ Notification fourthPage = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.fourth_page_content_title))
+ .setContentText(context.getString(R.string.fourth_page_content_text))
+ .extend(new NotificationCompat.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_large)
+ .setContentIconGravity(Gravity.START))
+ .build();
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationCompat.WearableExtender wearableOptions =
+ new NotificationCompat.WearableExtender()
+ .setHintHideIcon(true)
+ .setContentIcon(R.drawable.content_icon_small)
+ .addPage(secondPage)
+ .addPage(thirdPage)
+ .addPage(fourthPage);
+ applyBasicOptions(context, builder, wearableOptions, options);
+ builder.extend(wearableOptions);
+ return new Notification[] { builder.build() };
+ }
+ }
+
+ private static class MultiplePageNotificationPreset extends NotificationPreset {
+ public MultiplePageNotificationPreset() {
+ super(R.string.multiple_page_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.Builder secondPageBuilder = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.second_page_content_title))
+ .setContentText(context.getString(R.string.second_page_content_text));
+
+ NotificationCompat.Builder firstPageBuilder = new NotificationCompat.Builder(context);
+ NotificationCompat.WearableExtender firstPageWearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, firstPageBuilder, firstPageWearableOptions, options);
+
+ Integer firstBackground = options.backgroundIds == null
+ ? null : options.backgroundIds[0];
+ if (firstBackground != null) {
+ NotificationCompat.BigPictureStyle style =
+ new NotificationCompat.BigPictureStyle();
+ style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
+ firstBackground));
+ firstPageBuilder.setStyle(style);
+ }
+
+ Integer secondBackground = options.backgroundIds == null
+ ? null : options.backgroundIds[1];
+ if (secondBackground != null) {
+ NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
+ style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
+ secondBackground));
+ secondPageBuilder.setStyle(style);
+ }
+
+ firstPageBuilder.extend(
+ firstPageWearableOptions.addPage(secondPageBuilder.build()));
+
+ return new Notification[]{ firstPageBuilder.build() };
+ }
+
+ @Override
+ public int countBackgroundPickersRequired() {
+ return 2; // This sample does 2 pages notifications.
+ }
+ }
+
+ private static class NotificationBundlePreset extends NotificationPreset {
+ public NotificationBundlePreset() {
+ super(R.string.bundle_example, R.string.example_content_title,
+ R.string.example_content_text);
+ }
+
+ @Override
+ public Notification[] buildNotifications(Context context, BuildOptions options) {
+ NotificationCompat.Builder childBuilder1 = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.first_child_content_title))
+ .setContentText(context.getString(R.string.first_child_content_text))
+ .setSmallIcon(R.mipmap.ic_launcher)
+ .setLocalOnly(options.isLocalOnly)
+ .setGroup(EXAMPLE_GROUP_KEY)
+ .setSortKey("0");
+
+ NotificationCompat.Builder childBuilder2 = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.second_child_content_title))
+ .setContentText(context.getString(R.string.second_child_content_text))
+ .setSmallIcon(R.mipmap.ic_launcher)
+ .addAction(R.mipmap.ic_launcher,
+ context.getString(R.string.second_child_action),
+ NotificationUtil.getExamplePendingIntent(
+ context, R.string.second_child_action_clicked))
+ .setLocalOnly(options.isLocalOnly)
+ .setGroup(EXAMPLE_GROUP_KEY)
+ .setSortKey("1");
+
+ NotificationCompat.Builder summaryBuilder = new NotificationCompat.Builder(context)
+ .setGroup(EXAMPLE_GROUP_KEY)
+ .setGroupSummary(true);
+
+ NotificationCompat.WearableExtender summaryWearableOptions =
+ new NotificationCompat.WearableExtender();
+ applyBasicOptions(context, summaryBuilder, summaryWearableOptions, options);
+ summaryBuilder.extend(summaryWearableOptions);
+
+ return new Notification[] { summaryBuilder.build(), childBuilder1.build(),
+ childBuilder2.build() };
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationUtil.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationUtil.java
new file mode 100644
index 000000000..cd4b72c54
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/NotificationUtil.java
@@ -0,0 +1,20 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+public class NotificationUtil {
+ public static final String EXTRA_MESSAGE =
+ "com.example.android.support.wearable.notifications.MESSAGE";
+ public static final String EXTRA_REPLY =
+ "com.example.android.support.wearable.notifications.REPLY";
+
+ public static PendingIntent getExamplePendingIntent(Context context, int messageResId) {
+ Intent intent = new Intent(NotificationIntentReceiver.ACTION_EXAMPLE)
+ .setClass(context, NotificationIntentReceiver.class);
+ intent.putExtra(EXTRA_MESSAGE, context.getString(messageResId));
+ return PendingIntent.getBroadcast(context, messageResId /* requestCode */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPreset.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPreset.java
new file mode 100644
index 000000000..7a1682e75
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPreset.java
@@ -0,0 +1,16 @@
+package com.example.android.support.wearable.notifications;
+
+import android.support.v4.app.NotificationCompat;
+
+/**
+ * Base class for notification priority presets.
+ */
+public abstract class PriorityPreset extends NamedPreset {
+ public PriorityPreset(int nameResId) {
+ super(nameResId);
+ }
+
+ /** Apply the priority to a notification builder */
+ public abstract void apply(NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions);
+}
diff --git a/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPresets.java b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPresets.java
new file mode 100644
index 000000000..026f1aa8a
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/PriorityPresets.java
@@ -0,0 +1,39 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.support.v4.app.NotificationCompat;
+
+/**
+ * Collection of notification priority presets.
+ */
+public class PriorityPresets {
+ public static final PriorityPreset DEFAULT = new SimplePriorityPreset(
+ R.string.default_priority, Notification.PRIORITY_DEFAULT);
+
+ public static final PriorityPreset[] PRESETS = new PriorityPreset[] {
+ new SimplePriorityPreset(R.string.min_priority, Notification.PRIORITY_MIN),
+ new SimplePriorityPreset(R.string.low_priority, Notification.PRIORITY_LOW),
+ DEFAULT,
+ new SimplePriorityPreset(R.string.high_priority, Notification.PRIORITY_HIGH),
+ new SimplePriorityPreset(R.string.max_priority, Notification.PRIORITY_MAX)
+ };
+
+ /**
+ * Simple notification priority preset that sets a priority using
+ * {@link android.support.v4.app.NotificationCompat.Builder#setPriority}
+ */
+ private static class SimplePriorityPreset extends PriorityPreset {
+ private final int mPriority;
+
+ public SimplePriorityPreset(int nameResId, int priority) {
+ super(nameResId);
+ mPriority = priority;
+ }
+
+ @Override
+ public void apply(NotificationCompat.Builder builder,
+ NotificationCompat.WearableExtender wearableOptions) {
+ builder.setPriority(mPriority);
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/example_large_icon.png b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/example_large_icon.png
new file mode 100644
index 000000000..545f8cecb
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/example_large_icon.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_action.png b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_action.png
new file mode 100644
index 000000000..1f274990c
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_action.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_reply.png b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_reply.png
new file mode 100644
index 000000000..66388d5fa
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_full_reply.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_result_open.png b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_result_open.png
new file mode 100644
index 000000000..db8af57f7
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-hdpi/ic_result_open.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_action.png b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_action.png
new file mode 100644
index 000000000..b70b74ff5
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_action.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_reply.png b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_reply.png
new file mode 100644
index 000000000..60ce9f9c5
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_full_reply.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_result_open.png b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_result_open.png
new file mode 100644
index 000000000..860d7de6c
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-mdpi/ic_result_open.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_1.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_1.png
new file mode 100644
index 000000000..9c807946d
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_1.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_2.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_2.png
new file mode 100644
index 000000000..23d7062b3
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_2.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_3.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_3.png
new file mode 100644
index 000000000..588318ddd
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_3.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_4.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_4.png
new file mode 100644
index 000000000..bd1dfee00
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_4.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_5.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_5.png
new file mode 100644
index 000000000..aa1ad23af
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/bg_5.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_large.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_large.png
new file mode 100644
index 000000000..0eab3b10a
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_large.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_small.png b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_small.png
new file mode 100644
index 000000000..9a9f4b4b5
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/content_icon_small.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/example_big_picture.jpg b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/example_big_picture.jpg
new file mode 100644
index 000000000..68473ba6c
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-nodpi/example_big_picture.jpg differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_action.png b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_action.png
new file mode 100644
index 000000000..6a769521b
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_action.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_reply.png b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_reply.png
new file mode 100644
index 000000000..dba6fa7b0
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_full_reply.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_result_open.png b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_result_open.png
new file mode 100644
index 000000000..7d3c785c8
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/drawable-xhdpi/ic_result_open.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable/selected_background.xml b/samples/wearable/Notifications/Application/src/main/res/drawable/selected_background.xml
new file mode 100644
index 000000000..351774a88
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/drawable/selected_background.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/wearable/Notifications/Application/src/main/res/drawable/unselected_background.xml b/samples/wearable/Notifications/Application/src/main/res/drawable/unselected_background.xml
new file mode 100644
index 000000000..b9a43d1ef
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/drawable/unselected_background.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/wearable/Notifications/Application/src/main/res/layout/activity_main.xml b/samples/wearable/Notifications/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000..1f5794960
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/layout/background_picker.xml b/samples/wearable/Notifications/Application/src/main/res/layout/background_picker.xml
new file mode 100644
index 000000000..e4e295253
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/layout/background_picker.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/wearable/Notifications/Application/src/main/res/layout/layout_divider.xml b/samples/wearable/Notifications/Application/src/main/res/layout/layout_divider.xml
new file mode 100644
index 000000000..606c42bbf
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/layout/layout_divider.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/layout/simple_spinner_item.xml b/samples/wearable/Notifications/Application/src/main/res/layout/simple_spinner_item.xml
new file mode 100644
index 000000000..4eed3fac7
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/layout/simple_spinner_item.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/wearable/Notifications/Application/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..41479debe
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/wearable/Notifications/Application/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..380b02f45
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/wearable/Notifications/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..b3e251e0b
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/wearable/Notifications/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..1962289e7
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/wearable/Notifications/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..163f1f000
Binary files /dev/null and b/samples/wearable/Notifications/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Application/src/main/res/values/colors.xml b/samples/wearable/Notifications/Application/src/main/res/values/colors.xml
new file mode 100644
index 000000000..840978e0d
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/values/colors.xml
@@ -0,0 +1,4 @@
+
+
+ @android:color/holo_blue_bright
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/values/dimens.xml b/samples/wearable/Notifications/Application/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..8f4947f3a
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,13 @@
+
+
+ 16dp
+ 16dp
+
+ 12dp
+ 8dp
+ 8dp
+ 50dp
+
+ 48dp
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/values/strings.xml b/samples/wearable/Notifications/Application/src/main/res/values/strings.xml
new file mode 100644
index 000000000..84535e7e5
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/values/strings.xml
@@ -0,0 +1,178 @@
+
+
+
+ Wearable Notifications
+ Properties
+ Preset
+ Text
+ Title
+ Priority
+ Actions
+ Include large icon
+ Local only
+ Include content intent
+ Vibrate
+
+ Basic example
+ Stylized text example
+ Inbox example
+ Big picture example
+ Big text example
+ Bottom-aligned example
+ Gravity example
+ Content action example
+ Content icon example
+ Multiple page example
+ Bundle example
+
+ Min priority
+ Low priority
+ Default priority
+ High priority
+ Max priority
+
+ No actions
+ Single action
+ Single action with a long title
+ Reply action
+ Reply action with choices
+ Different on phone and wearable
+
+ Example action
+ Example action with a long title which wraps
+ Example reply action
+ Phone action
+ Wearable action
+
+ Example action clicked
+ Example reply action clicked
+ Phone action clicked
+ Wearable action clicked
+ Second child action clicked
+ Content intent clicked
+ Example content action clicked
+ Example content action 2 clicked
+ Example notification deleted
+
+ Basic example title
+ Basic example text
+
+ Big text example title
+ Big text example summary
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ anim id est laborum.
+
+
+ Inbox style example title
+ Inbox style example summary
+ Inbox style example line 1
+ Inbox style example line 2
+ Inbox style example line 3
+
+ Big picture style example title
+ Big picture style example summary
+
+ Second page title
+ Second page text
+
+ Third page title
+ Third page text
+
+ Fourth page title
+ Fourth page text
+
+ First child title
+
+ First child text. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua.
+ Second child title
+
+ Second child text. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua.
+ Second child action
+
+ Message?
+
+ Answer?
+ Yes
+ No
+ Maybe
+
+ Page %s background:
+
+
diff --git a/samples/wearable/Notifications/Application/src/main/res/values/styles.xml b/samples/wearable/Notifications/Application/src/main/res/values/styles.xml
new file mode 100644
index 000000000..7247b39b9
--- /dev/null
+++ b/samples/wearable/Notifications/Application/src/main/res/values/styles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/build.gradle b/samples/wearable/Notifications/Wearable/build.gradle
new file mode 100644
index 000000000..e339c0650
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'android'
+
+android {
+ compileSdkVersion 20
+ buildToolsVersion "19.1"
+
+ defaultConfig {
+ minSdkVersion 20
+ targetSdkVersion 20
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ runProguard false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
+
+dependencies {
+ compile "com.android.support:support-v13:20.0.+"
+ compile "com.google.android.support:wearable:1.0.+"
+}
diff --git a/samples/wearable/Notifications/Wearable/proguard-rules.txt b/samples/wearable/Notifications/Wearable/proguard-rules.txt
new file mode 100644
index 000000000..08e5bdc8d
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/proguard-rules.txt
@@ -0,0 +1,22 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+-dontwarn android.support.wearable.view.DelayedConfirmationView
+-dontwarn android.support.wearable.view.CircledImageView
diff --git a/samples/wearable/Notifications/Wearable/src/main/AndroidManifest.xml b/samples/wearable/Notifications/Wearable/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..32b5039ea
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/AndroidManifest.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/AnimatedNotificationDisplayActivity.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/AnimatedNotificationDisplayActivity.java
new file mode 100644
index 000000000..678d6e2ed
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/AnimatedNotificationDisplayActivity.java
@@ -0,0 +1,122 @@
+package com.example.android.support.wearable.notifications;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.Random;
+
+/**
+ * Custom display activity for an animated sample notification.
+ */
+public class AnimatedNotificationDisplayActivity extends Activity {
+ public static final String EXTRA_TITLE = "title";
+
+ private static final int BASE_ANIMATION_DURATION_MS = 2000;
+
+ private Random mRandom;
+ private int mAnimationRange;
+ private ImageView mImageView;
+ private Animator mAnimation;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_animated_notification_display);
+
+ mRandom = new Random(System.currentTimeMillis());
+ mAnimationRange = getResources().getDimensionPixelSize(R.dimen.animation_range);
+
+ String title = getIntent().getStringExtra(EXTRA_TITLE);
+ ((TextView) findViewById(R.id.title)).setText(title);
+
+ mImageView = new ImageView(this);
+ mImageView.setImageResource(R.drawable.example_big_picture);
+
+ ImageZoomView zoomView = new ImageZoomView(this, mImageView, mAnimationRange);
+ zoomView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ ((FrameLayout) findViewById(R.id.container)).addView(zoomView, 0);
+
+ createNextAnimation(false);
+ }
+
+ private void createNextAnimation(boolean start) {
+ float startX = mImageView.getTranslationX();
+ float startY = mImageView.getTranslationY();
+ float endX = -mRandom.nextInt(mAnimationRange);
+ float endY = -mRandom.nextInt(mAnimationRange);
+ float distance = (float) Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
+
+ mAnimation = ObjectAnimator.ofPropertyValuesHolder(mImageView,
+ PropertyValuesHolder.ofFloat("translationX", startX, endX),
+ PropertyValuesHolder.ofFloat("translationY", startY, endY));
+ mAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ mAnimation.setDuration(Math.max(BASE_ANIMATION_DURATION_MS / 10,
+ (int) (distance * BASE_ANIMATION_DURATION_MS / mAnimationRange)));
+
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ createNextAnimation(true);
+ }
+ });
+ if (start) {
+ mAnimation.start();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAnimation.start();
+ }
+
+ @Override
+ protected void onPause() {
+ mAnimation.pause();
+ super.onPause();
+ }
+
+ /** Helper view that zooms in on a child image view */
+ private static class ImageZoomView extends ViewGroup {
+ private final int mZoomLength;
+
+ public ImageZoomView(Context context, ImageView imageView, int zoomLength) {
+ super(context);
+ addView(imageView);
+ mZoomLength = zoomLength;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ ImageView imageView = (ImageView) getChildAt(0);
+
+ // Resize the image view to be at least mZoomLength pixels larger in both
+ // dimensions than the containing view.
+ int imageWidth = imageView.getDrawable().getIntrinsicWidth();
+ int imageHeight = imageView.getDrawable().getIntrinsicHeight();
+ int minSize = Math.max(right - left, bottom - top) + mZoomLength;
+ if (imageWidth > imageHeight) {
+ imageWidth = minSize * imageWidth / imageHeight;
+ imageHeight = minSize;
+ } else {
+ imageHeight = minSize * imageHeight / imageWidth;
+ imageWidth = minSize;
+ }
+ imageView.layout(left, top, left + imageWidth, top + imageHeight);
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/BasicNotificationDisplayActivity.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/BasicNotificationDisplayActivity.java
new file mode 100644
index 000000000..d394fb3b0
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/BasicNotificationDisplayActivity.java
@@ -0,0 +1,22 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Custom display activity for a sample notification.
+ */
+public class BasicNotificationDisplayActivity extends Activity {
+ public static final String EXTRA_TITLE = "title";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_notification_display);
+
+ String title = getIntent().getStringExtra(EXTRA_TITLE);
+
+ ((TextView) findViewById(R.id.title)).setText(title);
+ }
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
new file mode 100644
index 000000000..c3d16218f
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
@@ -0,0 +1,89 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.wearable.activity.WatchActivity;
+import android.support.wearable.view.WearableListView;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MainActivity extends WatchActivity implements WearableListView.ClickListener {
+ private static final int SAMPLE_NOTIFICATION_ID = 0;
+ public static final String KEY_REPLY = "reply";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ WearableListView listView = (WearableListView) findViewById(R.id.list);
+ listView.setAdapter(new Adapter(this));
+ listView.setClickListener(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (getIntent() != null) {
+ Bundle inputResults = RemoteInput.getResultsFromIntent(getIntent());
+ if (inputResults != null) {
+ CharSequence replyText = inputResults.getCharSequence(KEY_REPLY);
+ if (replyText != null) {
+ Toast.makeText(this, TextUtils.concat(getString(R.string.reply_was), replyText),
+ Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ }
+
+ /** Post a new or updated notification using the selected notification options. */
+ private void updateNotification(int presetIndex) {
+ NotificationPreset preset = NotificationPresets.PRESETS[presetIndex];
+ Notification notif = preset.buildNotification(this);
+ NotificationManagerCompat.from(this).notify(SAMPLE_NOTIFICATION_ID, notif);
+ finish();
+ }
+
+ @Override
+ public void onClick(WearableListView.ViewHolder v) {
+ updateNotification((Integer) v.itemView.getTag());
+ }
+
+ @Override
+ public void onTopEmptyRegionClick() {
+ }
+
+ private static final class Adapter extends WearableListView.Adapter {
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+
+ private Adapter(Context context) {
+ mContext = context;
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new WearableListView.ViewHolder(
+ mInflater.inflate(R.layout.notif_preset_list_item, null));
+ }
+
+ @Override
+ public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
+ TextView view = (TextView) holder.itemView.findViewById(R.id.name);
+ view.setText(mContext.getString(NotificationPresets.PRESETS[position].nameResId));
+ holder.itemView.setTag(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return NotificationPresets.PRESETS.length;
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java
new file mode 100644
index 000000000..7cfa1e871
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPreset.java
@@ -0,0 +1,18 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.content.Context;
+
+/**
+ * Base class for notification preset generators.
+ */
+public abstract class NotificationPreset {
+ public final int nameResId;
+
+ public NotificationPreset(int nameResId) {
+ this.nameResId = nameResId;
+ }
+
+ /** Start building a notification with this preset */
+ public abstract Notification buildNotification(Context context);
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java
new file mode 100644
index 000000000..451b270d8
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/NotificationPresets.java
@@ -0,0 +1,298 @@
+package com.example.android.support.wearable.notifications;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StrikethroughSpan;
+import android.text.style.StyleSpan;
+import android.text.style.SubscriptSpan;
+import android.text.style.SuperscriptSpan;
+import android.text.style.TypefaceSpan;
+import android.text.style.UnderlineSpan;
+import android.util.TypedValue;
+import android.view.Gravity;
+
+/**
+ * Collection of notification builder presets.
+ */
+public class NotificationPresets {
+ public static final NotificationPreset[] PRESETS = new NotificationPreset[] {
+ new BasicPreset(),
+ new StylizedTextPreset(),
+ new DisplayIntentPreset(),
+ new MultiSizeDisplayIntentPreset(),
+ new AnimatedDisplayIntentPreset(),
+ new ContentIconPreset()
+ };
+
+ private static Notification.Builder buildBasicNotification(Context context) {
+ return new Notification.Builder(context)
+ .setContentTitle(context.getString(R.string.example_content_title))
+ .setContentText(context.getString(R.string.example_content_text))
+ // Set a content intent to return to this sample
+ .setContentIntent(PendingIntent.getActivity(context, 0,
+ new Intent(context, MainActivity.class), 0))
+ .setSmallIcon(R.mipmap.ic_launcher);
+ }
+
+ private static class BasicPreset extends NotificationPreset {
+ public BasicPreset() {
+ super(R.string.basic_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
+ new Intent(context, MainActivity.class), 0);
+
+ Notification page2 = buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setHintShowBackgroundOnly(true)
+ .setBackground(BitmapFactory.decodeResource(context.getResources(),
+ R.drawable.example_big_picture)))
+ .build();
+
+ Notification page3 = buildBasicNotification(context)
+ .setContentTitle(context.getString(R.string.third_page))
+ .setContentText(null)
+ .extend(new Notification.WearableExtender()
+ .setContentAction(0 /* action A */))
+ .build();
+
+ SpannableStringBuilder choice2 = new SpannableStringBuilder(
+ "This choice is best");
+ choice2.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 5, 11, 0);
+
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .addAction(new Notification.Action(R.mipmap.ic_launcher,
+ context.getString(R.string.action_a), pendingIntent))
+ .addAction(new Notification.Action.Builder(R.mipmap.ic_launcher,
+ context.getString(R.string.reply), pendingIntent)
+ .addRemoteInput(new RemoteInput.Builder(MainActivity.KEY_REPLY)
+ .setChoices(new CharSequence[] {
+ context.getString(R.string.choice_1),
+ choice2 })
+ .build())
+ .build())
+ .addPage(page2)
+ .addPage(page3))
+ .build();
+ }
+ }
+
+ private static class StylizedTextPreset extends NotificationPreset {
+ public StylizedTextPreset() {
+ super(R.string.stylized_text_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ Notification.Builder builder = buildBasicNotification(context);
+
+ Notification.BigTextStyle style = new Notification.BigTextStyle();
+
+ SpannableStringBuilder title = new SpannableStringBuilder();
+ appendStyled(title, "Stylized", new StyleSpan(Typeface.BOLD_ITALIC));
+ title.append(" title");
+ SpannableStringBuilder text = new SpannableStringBuilder("Stylized text: ");
+ appendStyled(text, "C", new ForegroundColorSpan(Color.RED));
+ appendStyled(text, "O", new ForegroundColorSpan(Color.GREEN));
+ appendStyled(text, "L", new ForegroundColorSpan(Color.BLUE));
+ appendStyled(text, "O", new ForegroundColorSpan(Color.YELLOW));
+ appendStyled(text, "R", new ForegroundColorSpan(Color.MAGENTA));
+ appendStyled(text, "S", new ForegroundColorSpan(Color.CYAN));
+ text.append("; ");
+ appendStyled(text, "1.25x size", new RelativeSizeSpan(1.25f));
+ text.append("; ");
+ appendStyled(text, "0.75x size", new RelativeSizeSpan(0.75f));
+ text.append("; ");
+ appendStyled(text, "underline", new UnderlineSpan());
+ text.append("; ");
+ appendStyled(text, "strikethrough", new StrikethroughSpan());
+ text.append("; ");
+ appendStyled(text, "bold", new StyleSpan(Typeface.BOLD));
+ text.append("; ");
+ appendStyled(text, "italic", new StyleSpan(Typeface.ITALIC));
+ text.append("; ");
+ appendStyled(text, "sans-serif-thin", new TypefaceSpan("sans-serif-thin"));
+ text.append("; ");
+ appendStyled(text, "monospace", new TypefaceSpan("monospace"));
+ text.append("; ");
+ appendStyled(text, "sub", new SubscriptSpan());
+ text.append("script");
+ appendStyled(text, "super", new SuperscriptSpan());
+
+ style.setBigContentTitle(title);
+ style.bigText(text);
+
+ builder.setStyle(style);
+ return builder.build();
+ }
+
+ private void appendStyled(SpannableStringBuilder builder, String str, Object... spans) {
+ builder.append(str);
+ for (Object span : spans) {
+ builder.setSpan(span, builder.length() - str.length(), builder.length(), 0);
+ }
+ }
+ }
+
+ private static class DisplayIntentPreset extends NotificationPreset {
+ public DisplayIntentPreset() {
+ super(R.string.display_intent_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ Intent displayIntent = new Intent(context, BasicNotificationDisplayActivity.class);
+ displayIntent.putExtra(BasicNotificationDisplayActivity.EXTRA_TITLE,
+ context.getString(nameResId));
+ PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
+ 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(displayPendingIntent))
+ .build();
+ }
+ }
+
+ private static class MultiSizeDisplayIntentPreset extends NotificationPreset {
+ public MultiSizeDisplayIntentPreset() {
+ super(R.string.multisize_display_intent_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
+ new Intent(context, MainActivity.class), 0);
+ Intent displayIntent = new Intent(context, BasicNotificationDisplayActivity.class)
+ .putExtra(BasicNotificationDisplayActivity.EXTRA_TITLE,
+ context.getString(R.string.xsmall_sized_display));
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(PendingIntent.getActivity(context, 0, displayIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .addPage(createPageForSizePreset(context,
+ Notification.WearableExtender.SIZE_SMALL,
+ R.string.small_sized_display, 0))
+ .addPage(createPageForSizePreset(context,
+ Notification.WearableExtender.SIZE_MEDIUM,
+ R.string.medium_sized_display, 1))
+ .addPage(createPageForSizePreset(context,
+ Notification.WearableExtender.SIZE_LARGE,
+ R.string.large_sized_display, 2))
+ .addPage(createPageForSizePreset(context,
+ Notification.WearableExtender.SIZE_FULL_SCREEN,
+ R.string.full_screen_display, 3))
+ .addPage(createPageForCustomHeight(context, 256,
+ R.string.dp256_height_display))
+ .addPage(createPageForCustomHeight(context, 512,
+ R.string.dp512_height_display))
+ .addAction(new Notification.Action(R.mipmap.ic_launcher,
+ context.getString(R.string.action_a), pendingIntent))
+ .addAction(new Notification.Action(R.mipmap.ic_launcher,
+ context.getString(R.string.action_b), pendingIntent))
+ .addAction(new Notification.Action(R.mipmap.ic_launcher,
+ context.getString(R.string.action_c), pendingIntent))
+ .addAction(new Notification.Action(R.mipmap.ic_launcher,
+ context.getString(R.string.action_d), pendingIntent))
+ .setCustomSizePreset(Notification.WearableExtender.SIZE_XSMALL))
+ .build();
+ }
+
+ private Notification createPageForCustomHeight(Context context, int heightDisplayDp,
+ int pageNameResId) {
+ int contentHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ heightDisplayDp, context.getResources().getDisplayMetrics());
+ Intent displayIntent = new Intent(context, BasicNotificationDisplayActivity.class)
+ .setData(Uri.fromParts("example", "height/" + heightDisplayDp, null))
+ .putExtra(BasicNotificationDisplayActivity.EXTRA_TITLE,
+ context.getString(pageNameResId));
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(PendingIntent.getActivity(context, 0, displayIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setCustomContentHeight(contentHeight))
+ .build();
+ }
+
+ private Notification createPageForSizePreset(Context context, int sizePreset,
+ int pageNameResId, int contentAction) {
+ Intent displayIntent = new Intent(context, BasicNotificationDisplayActivity.class)
+ .setData(Uri.fromParts("example", "size/" + sizePreset, null))
+ .putExtra(BasicNotificationDisplayActivity.EXTRA_TITLE,
+ context.getString(pageNameResId));
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(PendingIntent.getActivity(context, 0, displayIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setCustomSizePreset(sizePreset)
+ .setContentAction(contentAction))
+ .build();
+ }
+ }
+
+ private static class AnimatedDisplayIntentPreset extends NotificationPreset {
+ public AnimatedDisplayIntentPreset() {
+ super(R.string.animated_display_intent_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ Intent displayIntent = new Intent(context, AnimatedNotificationDisplayActivity.class);
+ displayIntent.putExtra(BasicNotificationDisplayActivity.EXTRA_TITLE,
+ context.getString(nameResId));
+ PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
+ 0, displayIntent, 0);
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(displayPendingIntent))
+ .build();
+ }
+ }
+
+ private static class ContentIconPreset extends NotificationPreset {
+ public ContentIconPreset() {
+ super(R.string.content_icon_example);
+ }
+
+ @Override
+ public Notification buildNotification(Context context) {
+ Notification page2 = buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_small)
+ .setContentIconGravity(Gravity.START))
+ .build();
+
+ Notification page3 = buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_large))
+ .build();
+
+ Notification page4 = buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setContentIcon(R.drawable.content_icon_large)
+ .setContentIconGravity(Gravity.START))
+ .build();
+
+ return buildBasicNotification(context)
+ .extend(new Notification.WearableExtender()
+ .setHintHideIcon(true)
+ .setContentIcon(R.drawable.content_icon_small)
+ .addPage(page2)
+ .addPage(page3)
+ .addPage(page4))
+ .build();
+ }
+ }
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java
new file mode 100644
index 000000000..4b2c1dbf6
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java
@@ -0,0 +1,75 @@
+package com.example.android.support.wearable.notifications;
+
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
+import android.support.wearable.view.WearableListView;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class WearableListItemLayout extends LinearLayout implements WearableListView.Item {
+
+ private final float mFadedTextAlpha;
+ private final int mFadedCircleColor;
+ private final int mChosenCircleColor;
+ private ImageView mCircle;
+ private float mScale;
+ private TextView mName;
+
+ public WearableListItemLayout(Context context) {
+ this(context, null);
+ }
+
+ public WearableListItemLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public WearableListItemLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mFadedTextAlpha = getResources().getInteger(R.integer.action_text_faded_alpha) / 100f;
+ mFadedCircleColor = getResources().getColor(R.color.wl_gray);
+ mChosenCircleColor = getResources().getColor(R.color.wl_blue);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mCircle = (ImageView) findViewById(R.id.circle);
+ mName = (TextView) findViewById(R.id.name);
+ }
+
+ @Override
+ public float getProximityMinValue() {
+ return 1f;
+ }
+
+ @Override
+ public float getProximityMaxValue() {
+ return 1.6f;
+ }
+
+ @Override
+ public float getCurrentProximityValue() {
+ return mScale;
+ }
+
+ @Override
+ public void setScalingAnimatorValue(float scale) {
+ mScale = scale;
+ mCircle.setScaleX(scale);
+ mCircle.setScaleY(scale);
+ }
+
+ @Override
+ public void onScaleUpStart() {
+ mName.setAlpha(1f);
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
+ }
+
+ @Override
+ public void onScaleDownStart() {
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
+ mName.setAlpha(mFadedTextAlpha);
+ }
+}
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_large.png b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_large.png
new file mode 100644
index 000000000..0eab3b10a
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_large.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_small.png b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_small.png
new file mode 100644
index 000000000..9a9f4b4b5
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/content_icon_small.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/example_big_picture.jpg b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/example_big_picture.jpg
new file mode 100644
index 000000000..68473ba6c
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/drawable-nodpi/example_big_picture.jpg differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/drawable/wl_circle.xml b/samples/wearable/Notifications/Wearable/src/main/res/drawable/wl_circle.xml
new file mode 100644
index 000000000..a06c53a8d
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/drawable/wl_circle.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_animated_notification_display.xml b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_animated_notification_display.xml
new file mode 100644
index 000000000..285b11707
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_animated_notification_display.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_main.xml b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000..0a3eb7625
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_main.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml
new file mode 100644
index 000000000..02b61db85
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/layout/notif_preset_list_item.xml b/samples/wearable/Notifications/Wearable/src/main/res/layout/notif_preset_list_item.xml
new file mode 100644
index 000000000..68670f47e
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/layout/notif_preset_list_item.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..41479debe
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..380b02f45
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..b3e251e0b
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..1962289e7
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..163f1f000
Binary files /dev/null and b/samples/wearable/Notifications/Wearable/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/values/colors.xml b/samples/wearable/Notifications/Wearable/src/main/res/values/colors.xml
new file mode 100644
index 000000000..a8bb87b7e
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #2878ff
+ #c1c1c1
+ #434343
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/values/dimens.xml b/samples/wearable/Notifications/Wearable/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..9eaca9889
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 16dp
+ 16dp
+ 60dp
+
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/values/integers.xml b/samples/wearable/Notifications/Wearable/src/main/res/values/integers.xml
new file mode 100644
index 000000000..c3bc25215
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/values/integers.xml
@@ -0,0 +1,4 @@
+
+
+ 40
+
diff --git a/samples/wearable/Notifications/Wearable/src/main/res/values/strings.xml b/samples/wearable/Notifications/Wearable/src/main/res/values/strings.xml
new file mode 100644
index 000000000..7c12e3178
--- /dev/null
+++ b/samples/wearable/Notifications/Wearable/src/main/res/values/strings.xml
@@ -0,0 +1,31 @@
+
+
+
+ Wearable Notifications
+ Basic example
+ Stylized text example
+ Display intent example
+ Multiple-sized display intent example
+ Animated display intent example
+ Content icon example
+
+ Example content title
+ Example content text
+
+ X-Small sized display
+ Small sized display
+ Medium sized display
+ Large sized display
+ Full-Screen display
+ 256dp height display
+ 512dp height display
+
+ Action A
+ Action B
+ Action C
+ Action D
+ Reply
+ Reply was:
+ Third page
+ Choice #1
+
diff --git a/samples/wearable/Notifications/build.gradle b/samples/wearable/Notifications/build.gradle
new file mode 100644
index 000000000..8bafed410
--- /dev/null
+++ b/samples/wearable/Notifications/build.gradle
@@ -0,0 +1,14 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.11.+'
+ }
+}
+
+allprojects {
+ repositories {
+ mavenCentral()
+ }
+}
diff --git a/samples/wearable/Notifications/gradle.properties b/samples/wearable/Notifications/gradle.properties
new file mode 100644
index 000000000..5d08ba75b
--- /dev/null
+++ b/samples/wearable/Notifications/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Settings specified in this file will override any Gradle settings
+# configured through the IDE.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.jar b/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..583859812
Binary files /dev/null and b/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.properties b/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..e83e46081
--- /dev/null
+++ b/samples/wearable/Notifications/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Mar 14 14:02:22 PDT 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip
diff --git a/samples/wearable/Notifications/gradlew b/samples/wearable/Notifications/gradlew
new file mode 100755
index 000000000..91a7e269e
--- /dev/null
+++ b/samples/wearable/Notifications/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/samples/wearable/Notifications/gradlew.bat b/samples/wearable/Notifications/gradlew.bat
new file mode 100755
index 000000000..aec99730b
--- /dev/null
+++ b/samples/wearable/Notifications/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/wearable/Notifications/settings.gradle b/samples/wearable/Notifications/settings.gradle
new file mode 100644
index 000000000..f3f25a547
--- /dev/null
+++ b/samples/wearable/Notifications/settings.gradle
@@ -0,0 +1 @@
+include 'Wearable', 'Application'
diff --git a/samples/wearable/build.gradle b/samples/wearable/build.gradle
new file mode 100644
index 000000000..19c1596dd
--- /dev/null
+++ b/samples/wearable/build.gradle
@@ -0,0 +1,30 @@
+buildscript {
+ ext.topDir = file('../../../../../')
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.11.+'
+ }
+}
+
+List samples = [
+ "Notifications"
+]
+
+List taskNames = [
+ "clean",
+ "build",
+]
+
+taskNames.each { taskName ->
+ def task = project.hasProperty(taskName) ? project.tasks[taskName] : project.task(taskName)
+ samples.each { sample ->
+ File sampleDir = new File(sample)
+ task.dependsOn project.task([type: GradleBuild], "${sample}_${taskName}", {
+ buildFile = "${sample}/build.gradle"
+ dir = sample
+ tasks = [taskName]
+ })
+ }
+}
diff --git a/samples/wearable/gradle/wrapper/gradle-wrapper.jar b/samples/wearable/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..583859812
Binary files /dev/null and b/samples/wearable/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/wearable/gradle/wrapper/gradle-wrapper.properties b/samples/wearable/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..e83e46081
--- /dev/null
+++ b/samples/wearable/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Mar 14 14:02:22 PDT 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip
diff --git a/samples/wearable/gradlew b/samples/wearable/gradlew
new file mode 100755
index 000000000..871802d5f
--- /dev/null
+++ b/samples/wearable/gradlew
@@ -0,0 +1,174 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+# Change the project's .gradle to the android out dir.
+ANDROID_GRADLE_ROOT="$APP_HOME/../../../../out/host/gradle/tools/updater"
+if [[ -z "$ANDROID_CACHE_DIR" ]]; then
+ ANDROID_CACHE_DIR="$ANDROID_GRADLE_ROOT/.gradle"
+fi
+
+# Change the local user directories to be under the android out dir
+export GRADLE_USER_HOME="$ANDROID_GRADLE_ROOT/.gradle"
+export M2_HOME="$ANDROID_GRADLE_ROOT/.m2"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/samples/wearable/gradlew.bat b/samples/wearable/gradlew.bat
new file mode 100755
index 000000000..aec99730b
--- /dev/null
+++ b/samples/wearable/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/wearable/settings.gradle b/samples/wearable/settings.gradle
new file mode 100644
index 000000000..e69de29bb