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:

+ +

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