diff options
35 files changed, 1113 insertions, 15 deletions
diff --git a/build/sdk.atree b/build/sdk.atree index 674483790..275e8d7f4 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -287,21 +287,22 @@ developers/build/prebuilts/gradle/JobScheduler sam developers/build/prebuilts/androidtv samples/${PLATFORM_NAME}/androidtv # Wearable sample tree -development/samples/wearable/AgendaData samples/${PLATFORM_NAME}/wearable/AgendaData -development/samples/wearable/DataLayer samples/${PLATFORM_NAME}/wearable/DataLayer -development/samples/wearable/DelayedConfirmation samples/${PLATFORM_NAME}/wearable/DelayedConfirmation -development/samples/wearable/ElizaChat samples/${PLATFORM_NAME}/wearable/ElizaChat -development/samples/wearable/FindMyPhone samples/${PLATFORM_NAME}/wearable/FindMyPhone -development/samples/wearable/Flashlight samples/${PLATFORM_NAME}/wearable/Flashlight -development/samples/wearable/Geofencing samples/${PLATFORM_NAME}/wearable/Geofencing -development/samples/wearable/GridViewPager samples/${PLATFORM_NAME}/wearable/GridViewPager -development/samples/wearable/JumpingJack samples/${PLATFORM_NAME}/wearable/JumpingJack -development/samples/wearable/Notifications samples/${PLATFORM_NAME}/wearable/Notifications -development/samples/wearable/Quiz samples/${PLATFORM_NAME}/wearable/Quiz -development/samples/wearable/RecipeAssistant samples/${PLATFORM_NAME}/wearable/RecipeAssistant -development/samples/wearable/SkeletonWearableApp samples/${PLATFORM_NAME}/wearable/SkeletonWearableApp -development/samples/wearable/Timer samples/${PLATFORM_NAME}/wearable/Timer -development/samples/wearable/WatchViewStub samples/${PLATFORM_NAME}/wearable/WatchViewStub +development/samples/wearable/AgendaData samples/${PLATFORM_NAME}/wearable/AgendaData +development/samples/wearable/DataLayer samples/${PLATFORM_NAME}/wearable/DataLayer +development/samples/wearable/DelayedConfirmation samples/${PLATFORM_NAME}/wearable/DelayedConfirmation +development/samples/wearable/ElizaChat samples/${PLATFORM_NAME}/wearable/ElizaChat +development/samples/wearable/FindMyPhone samples/${PLATFORM_NAME}/wearable/FindMyPhone +development/samples/wearable/Flashlight samples/${PLATFORM_NAME}/wearable/Flashlight +development/samples/wearable/Geofencing samples/${PLATFORM_NAME}/wearable/Geofencing +development/samples/wearable/GridViewPager samples/${PLATFORM_NAME}/wearable/GridViewPager +development/samples/wearable/JumpingJack samples/${PLATFORM_NAME}/wearable/JumpingJack +development/samples/wearable/Notifications samples/${PLATFORM_NAME}/wearable/Notifications +development/samples/wearable/Quiz samples/${PLATFORM_NAME}/wearable/Quiz +development/samples/wearable/RecipeAssistant samples/${PLATFORM_NAME}/wearable/RecipeAssistant +development/samples/wearable/SkeletonWearableApp samples/${PLATFORM_NAME}/wearable/SkeletonWearableApp +development/samples/wearable/SynchronizedNotifications samples/${PLATFORM_NAME}/wearable/SynchronizedNotifications +development/samples/wearable/Timer samples/${PLATFORM_NAME}/wearable/Timer +development/samples/wearable/WatchViewStub samples/${PLATFORM_NAME}/wearable/WatchViewStub # Old sample tree development/samples/AccelerometerPlay samples/${PLATFORM_NAME}/legacy/AccelerometerPlay diff --git a/samples/wearable/SynchronizedNotifications/Application/build.gradle b/samples/wearable/SynchronizedNotifications/Application/build.gradle new file mode 100644 index 000000000..a850a8d61 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'android' + +android { + compileSdkVersion 19 + buildToolsVersion '20' + defaultConfig { + minSdkVersion 18 + targetSdkVersion 19 + versionCode 1 + versionName '1.0' + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + compile 'com.google.android.gms:play-services:5.0.+@aar' + compile 'com.android.support:support-v13:20.0.+' + compile project(':Common') + wearApp project(':Wearable') +} diff --git a/samples/wearable/SynchronizedNotifications/Application/proguard-rules.txt b/samples/wearable/SynchronizedNotifications/Application/proguard-rules.txt new file mode 100644 index 000000000..5b86c0858 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/proguard-rules.txt @@ -0,0 +1,17 @@ +# 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 proguardFiles +# directive in build.gradle. +# +# 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 *; +#} diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/AndroidManifest.xml b/samples/wearable/SynchronizedNotifications/Application/src/main/AndroidManifest.xml new file mode 100644 index 000000000..60960a8a8 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.wearable.synchronizednotifications" > + <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="19" /> + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@android:style/Theme.DeviceDefault.Light" > + <meta-data android:name="com.google.android.gms.version" + android:value="@integer/google_play_services_version" /> + <activity + android:name=".PhoneActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <service android:name=".DismissListener"> + <intent-filter> + <action + android:name="com.google.android.gms.wearable.BIND_LISTENER" /> + </intent-filter> + <intent-filter> + <action + android:name="com.example.android.wearable.synchronizednotifications.DISMISS" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/DismissListener.java b/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/DismissListener.java new file mode 100644 index 000000000..98747f55b --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/DismissListener.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.wearable.synchronizednotifications; + +import static com.google.android.gms.wearable.PutDataRequest.WEAR_URI_SCHEME; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.NotificationManagerCompat; +import android.util.Log; + +import com.example.android.wearable.synchronizednotifications.common.Constants; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.wearable.DataApi; +import com.google.android.gms.wearable.DataEvent; +import com.google.android.gms.wearable.DataEventBuffer; +import com.google.android.gms.wearable.PutDataMapRequest; +import com.google.android.gms.wearable.Wearable; +import com.google.android.gms.wearable.WearableListenerService; + +/** + * A {@link com.google.android.gms.wearable.WearableListenerService} that is invoked when certain + * notifications are dismissed from either the phone or watch. + */ +public class DismissListener extends WearableListenerService + implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, + ResultCallback<DataApi.DeleteDataItemsResult> { + + private static final String TAG = "DismissListener"; + private GoogleApiClient mGoogleApiClient; + + @Override + public void onCreate() { + super.onCreate(); + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Wearable.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + @Override + public void onDataChanged(DataEventBuffer dataEvents) { + for (DataEvent dataEvent : dataEvents) { + if (dataEvent.getType() == DataEvent.TYPE_DELETED) { + if (Constants.BOTH_PATH.equals(dataEvent.getDataItem().getUri().getPath())) { + // notification on the phone should be dismissed + NotificationManagerCompat.from(this).cancel(Constants.BOTH_ID); + } + } + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (null != intent) { + String action = intent.getAction(); + if (Constants.ACTION_DISMISS.equals(action)) { + // We need to dismiss the wearable notification. We delete the DataItem that + // created the notification to inform the wearable. + int notificationId = intent.getIntExtra(Constants.KEY_NOTIFICATION_ID, -1); + if (notificationId == Constants.BOTH_ID) { + dismissWearableNotification(notificationId); + } + } + } + return super.onStartCommand(intent, flags, startId); + } + + /** + * Removes the DataItem that was used to create a notification on the watch. By deleting the + * data item, a {@link com.google.android.gms.wearable.WearableListenerService} on the watch + * will be notified and the notification on the watch will be removed. + * + * @param id The ID of the notification that should be removed + */ + private void dismissWearableNotification(final int id) { + mGoogleApiClient.connect(); + } + + @Override // ConnectionCallbacks + public void onConnected(Bundle bundle) { + final Uri dataItemUri = + new Uri.Builder().scheme(WEAR_URI_SCHEME).path(Constants.BOTH_PATH).build(); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Deleting Uri: " + dataItemUri.toString()); + } + Wearable.DataApi.deleteDataItems( + mGoogleApiClient, dataItemUri).setResultCallback(this); + } + + @Override // ConnectionCallbacks + public void onConnectionSuspended(int i) { + } + + @Override // OnConnectionFailedListener + public void onConnectionFailed(ConnectionResult connectionResult) { + Log.e(TAG, "Failed to connect to the Google API client"); + } + + @Override // ResultCallback<DataApi.DeleteDataItemsResult> + public void onResult(DataApi.DeleteDataItemsResult deleteDataItemsResult) { + if (!deleteDataItemsResult.getStatus().isSuccess()) { + Log.e(TAG, "dismissWearableNotification(): failed to delete DataItem"); + } + mGoogleApiClient.disconnect(); + } +} diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/PhoneActivity.java b/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/PhoneActivity.java new file mode 100644 index 000000000..2cac13751 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/java/com/example/android/wearable/synchronizednotifications/PhoneActivity.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.wearable.synchronizednotifications; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.util.Log; +import android.view.View; + +import com.example.android.wearable.synchronizednotifications.common.Constants; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.wearable.DataApi; +import com.google.android.gms.wearable.PutDataMapRequest; +import com.google.android.gms.wearable.PutDataRequest; +import com.google.android.gms.wearable.Wearable; + +import java.text.DateFormat; +import java.util.Date; + +/** + * A simple activity that presents three buttons that would trigger three different combinations of + * notifications on the handset and the watch: + * <ul> + * <li>The first button builds a simple local-only notification on the handset.</li> + * <li>The second one creates a wearable-only notification by putting a data item in the shared data + * store and having a {@link com.google.android.gms.wearable.WearableListenerService} listen for + * that on the wearable</li> + * <li>The third one creates a local notification and a wearable notification by combining the above + * two. It, however, demonstrates how one can set things up so that the dismissal of one + * notification results in the dismissal of the other one.</li> + * </ul> + */ +public class PhoneActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener { + + private static final String TAG = "PhoneActivity"; + private GoogleApiClient mGoogleApiClient; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_phone); + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Wearable.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + /** + * Builds a local-only notification for the handset. This is achieved by using + * <code>setLocalOnly(true)</code>. If <code>withDismissal</code> is set to <code>true</code>, a + * {@link android.app.PendingIntent} will be added to handle the dismissal of notification to + * be able to remove the mirrored notification on the wearable. + */ + private void buildLocalOnlyNotification(String title, String content, int notificationId, + boolean withDismissal) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + builder.setContentTitle(title) + .setContentText(content) + .setLocalOnly(true) + .setSmallIcon(R.drawable.ic_launcher); + + if (withDismissal) { + Intent dismissIntent = new Intent(Constants.ACTION_DISMISS); + dismissIntent.putExtra(Constants.KEY_NOTIFICATION_ID, Constants.BOTH_ID); + PendingIntent pendingIntent = PendingIntent + .getService(this, 0, dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setDeleteIntent(pendingIntent); + } + NotificationManagerCompat.from(this).notify(notificationId, builder.build()); + } + + /** + * Builds a DataItem that on the wearable will be interpreted as a request to show a + * notification. The result will be a notification that only shows up on the wearable. + */ + private void buildWearableOnlyNotification(String title, String content, String path) { + if (mGoogleApiClient.isConnected()) { + PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path); + putDataMapRequest.getDataMap().putString(Constants.KEY_CONTENT, content); + putDataMapRequest.getDataMap().putString(Constants.KEY_TITLE, title); + PutDataRequest request = putDataMapRequest.asPutDataRequest(); + Wearable.DataApi.putDataItem(mGoogleApiClient, request) + .setResultCallback(new ResultCallback<DataApi.DataItemResult>() { + @Override + public void onResult(DataApi.DataItemResult dataItemResult) { + if (!dataItemResult.getStatus().isSuccess()) { + Log.e(TAG, "buildWatchOnlyNotification(): Failed to set the data, " + + "status: " + dataItemResult.getStatus().getStatusCode()); + } + } + }); + } else { + Log.e(TAG, "buildWearableOnlyNotification(): no Google API Client connection"); + } + } + + /** + * Builds a local notification and sets a DataItem that will be interpreted by the wearable as + * a request to build a notification on the wearable as as well. The two notifications show + * different messages. + * Dismissing either of the notifications will result in dismissal of the other; this is + * achieved by creating a {@link android.app.PendingIntent} that results in removal of + * the DataItem that created the watch notification. The deletion of the DataItem is observed on + * both sides, using WearableListenerService callbacks, and is interpreted on each side as a + * request to dismiss the corresponding notification. + */ + private void buildMirroredNotifications(String phoneTitle, String watchTitle, String content) { + if (mGoogleApiClient.isConnected()) { + // Wearable notification + buildWearableOnlyNotification(watchTitle, content, Constants.BOTH_PATH); + + // Local notification, with a pending intent for dismissal + buildLocalOnlyNotification(phoneTitle, content, Constants.BOTH_ID, true); + } + } + + @Override + protected void onStart() { + super.onStart(); + mGoogleApiClient.connect(); + } + + @Override + protected void onStop() { + mGoogleApiClient.disconnect(); + super.onStop(); + } + + @Override + public void onConnected(Bundle bundle) { + } + + @Override + public void onConnectionSuspended(int i) { + } + + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + Log.e(TAG, "Failed to connect to Google API Client"); + } + + /** + * Returns a string built from the current time + */ + private String now() { + DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(this); + return dateFormat.format(new Date()); + } + + /** + * Handles button clicks in the UI. + */ + public void onClick(View view) { + int id = view.getId(); + switch (id) { + case R.id.phone_only: + buildLocalOnlyNotification(getString(R.string.phone_only), now(), + Constants.PHONE_ONLY_ID, false); + break; + case R.id.wear_only: + buildWearableOnlyNotification(getString(R.string.wear_only), now(), + Constants.WATCH_ONLY_PATH); + break; + case R.id.different_notifications: + buildMirroredNotifications(getString(R.string.phone_both), getString(R.string.watch_both), now()); + break; + } + } +} diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..f7dd9a0bd --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..fef2da78f --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..f2fb03cdd --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..944042ca8 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/layout/activity_phone.xml b/samples/wearable/SynchronizedNotifications/Application/src/main/res/layout/activity_phone.xml new file mode 100644 index 000000000..140c4e8c3 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/layout/activity_phone.xml @@ -0,0 +1,41 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + tools:context=".PhoneActivity"> + + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/phone_only" + android:id="@+id/phone_only" + android:onClick="onClick" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" /> + + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/wear_only" + android:id="@+id/wear_only" + android:onClick="onClick" + android:layout_below="@+id/phone_only" + android:layout_alignLeft="@+id/phone_only" + android:layout_marginTop="30dp" + android:layout_alignRight="@+id/phone_only" /> + + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/different_notifications" + android:id="@+id/different_notifications" + android:layout_below="@+id/wear_only" + android:onClick="onClick" + android:layout_alignLeft="@+id/wear_only" + android:layout_marginTop="30dp" + android:layout_alignRight="@+id/wear_only" /> +</RelativeLayout> diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/dimens.xml b/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/dimens.xml new file mode 100644 index 000000000..47c822467 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/strings.xml b/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/strings.xml new file mode 100644 index 000000000..52d85489b --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Application/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Synchronized Notifications</string> + <string name="wear_only">Watch Only Notification</string> + <string name="phone_only">Phone Only Notification</string> + <string name="different_notifications">Different Notifications</string> + <string name="phone_both">Phone Notification</string> + <string name="watch_both">Watch Notification</string> + +</resources> diff --git a/samples/wearable/SynchronizedNotifications/Common/build.gradle b/samples/wearable/SynchronizedNotifications/Common/build.gradle new file mode 100644 index 000000000..f87e44cf7 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Common/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'android-library' + +android { + compileSdkVersion 19 + buildToolsVersion '20' + defaultConfig { + minSdkVersion 18 + targetSdkVersion 19 + versionCode 1 + versionName '1.0' + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + productFlavors { + } +} diff --git a/samples/wearable/SynchronizedNotifications/Common/proguard-rules.txt b/samples/wearable/SynchronizedNotifications/Common/proguard-rules.txt new file mode 100644 index 000000000..f4a05360a --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Common/proguard-rules.txt @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# 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 *; +#} diff --git a/samples/wearable/SynchronizedNotifications/Common/src/main/AndroidManifest.xml b/samples/wearable/SynchronizedNotifications/Common/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c07d858b9 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Common/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.wearable.synchronizednotifications.common"> + + <application android:allowBackup="true" + android:label="@string/app_name"> + </application> + +</manifest> diff --git a/samples/wearable/SynchronizedNotifications/Common/src/main/java/com/example/android/wearable/synchronizednotifications/common/Constants.java b/samples/wearable/SynchronizedNotifications/Common/src/main/java/com/example/android/wearable/synchronizednotifications/common/Constants.java new file mode 100644 index 000000000..693533f5d --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Common/src/main/java/com/example/android/wearable/synchronizednotifications/common/Constants.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.wearable.synchronizednotifications.common; + +/** + * Constants that are used in both the Application and the Wearable modules. + */ +public final class Constants { + + private Constants() {}; + + public static final int WATCH_ONLY_ID = 2; + public static final int PHONE_ONLY_ID = 3; + public static final int BOTH_ID = 4; + + public static final String BOTH_PATH = "/both"; + public static final String WATCH_ONLY_PATH = "/watch-only"; + public static final String KEY_NOTIFICATION_ID = "notification-id"; + public static final String KEY_TITLE = "title"; + public static final String KEY_CONTENT = "content"; + + public static final String ACTION_DISMISS + = "com.example.android.wearable.synchronizednotifications.DISMISS"; +} diff --git a/samples/wearable/SynchronizedNotifications/Common/src/main/res/values/strings.xml b/samples/wearable/SynchronizedNotifications/Common/src/main/res/values/strings.xml new file mode 100644 index 000000000..b28ef6067 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Common/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">Common</string> +</resources> diff --git a/samples/wearable/SynchronizedNotifications/Wearable/build.gradle b/samples/wearable/SynchronizedNotifications/Wearable/build.gradle new file mode 100644 index 000000000..c82a8dec5 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'android' + +android { + compileSdkVersion 20 + buildToolsVersion '20' + defaultConfig { + minSdkVersion 20 + targetSdkVersion 20 + versionCode 1 + versionName '1.0' + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + compile 'com.google.android.gms:play-services:5.0.+@aar' + compile 'com.android.support:support-v13:20.0.+' + compile 'com.google.android.support:wearable:1.0.+' + compile project(':Common') +} diff --git a/samples/wearable/SynchronizedNotifications/Wearable/proguard-rules.txt b/samples/wearable/SynchronizedNotifications/Wearable/proguard-rules.txt new file mode 100644 index 000000000..5b86c0858 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/proguard-rules.txt @@ -0,0 +1,17 @@ +# 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 proguardFiles +# directive in build.gradle. +# +# 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 *; +#} diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml b/samples/wearable/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ec2f7fee0 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.wearable.synchronizednotifications" > + + <uses-sdk android:minSdkVersion="20" android:targetSdkVersion="20" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@android:style/Theme.DeviceDefault.Light" > + <meta-data android:name="com.google.android.gms.version" + android:value="@integer/google_play_services_version" /> + <activity + android:name=".WearableActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <service android:name=".NotificationUpdateService"> + <intent-filter> + <action + android:name="com.google.android.gms.wearable.BIND_LISTENER" /> + </intent-filter> + <intent-filter> + <action + android:name="com.example.android.wearable.synchronizednotifications.DISMISS" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/NotificationUpdateService.java b/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/NotificationUpdateService.java new file mode 100644 index 000000000..d701ab142 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/NotificationUpdateService.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.wearable.synchronizednotifications; + +import static com.google.android.gms.wearable.PutDataRequest.WEAR_URI_SCHEME; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +import com.example.android.wearable.synchronizednotifications.common.Constants; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.wearable.DataApi; +import com.google.android.gms.wearable.DataEvent; +import com.google.android.gms.wearable.DataEventBuffer; +import com.google.android.gms.wearable.DataMap; +import com.google.android.gms.wearable.DataMapItem; +import com.google.android.gms.wearable.PutDataMapRequest; +import com.google.android.gms.wearable.Wearable; +import com.google.android.gms.wearable.WearableListenerService; + +/** + * A {@link com.google.android.gms.wearable.WearableListenerService} that will be invoked when a + * DataItem is added or deleted. The creation of a new DataItem will be interpreted as a request to + * create a new notification and the removal of that DataItem is interpreted as a request to + * dismiss that notification. + */ +public class NotificationUpdateService extends WearableListenerService + implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, + ResultCallback<DataApi.DeleteDataItemsResult> { + + private static final String TAG = "NotificationUpdate"; + private GoogleApiClient mGoogleApiClient; + + @Override + public void onCreate() { + super.onCreate(); + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Wearable.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (null != intent) { + String action = intent.getAction(); + if (Constants.ACTION_DISMISS.equals(action)) { + // We need to dismiss the wearable notification. We delete the data item that + // created the notification and that is how we inform the phone + int notificationId = intent.getIntExtra(Constants.KEY_NOTIFICATION_ID, -1); + if (notificationId == Constants.BOTH_ID) { + dismissPhoneNotification(notificationId); + } + } + } + return super.onStartCommand(intent, flags, startId); + } + + /** + * Dismisses the phone notification, via a {@link android.app.PendingIntent} that is triggered + * when the user dismisses the local notification. Deleting the corresponding data item notifies + * the {@link com.google.android.gms.wearable.WearableListenerService} on the phone that the + * matching notification on the phone side should be removed. + */ + private void dismissPhoneNotification(int id) { + mGoogleApiClient.connect(); + } + + @Override + public void onDataChanged(DataEventBuffer dataEvents) { + for (DataEvent dataEvent : dataEvents) { + if (dataEvent.getType() == DataEvent.TYPE_CHANGED) { + DataMap dataMap = DataMapItem.fromDataItem(dataEvent.getDataItem()).getDataMap(); + String content = dataMap.getString(Constants.KEY_CONTENT); + String title = dataMap.getString(Constants.KEY_TITLE); + if (Constants.WATCH_ONLY_PATH.equals(dataEvent.getDataItem().getUri().getPath())) { + buildWearableOnlyNotification(title, content, false); + } else if (Constants.BOTH_PATH.equals(dataEvent.getDataItem().getUri().getPath())) { + buildWearableOnlyNotification(title, content, true); + } + } else if (dataEvent.getType() == DataEvent.TYPE_DELETED) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "DataItem deleted: " + dataEvent.getDataItem().getUri().getPath()); + } + if (Constants.BOTH_PATH.equals(dataEvent.getDataItem().getUri().getPath())) { + // Dismiss the corresponding notification + ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)) + .cancel(Constants.BOTH_ID); + } + } + } + } + + /** + * Builds a simple notification on the wearable. + */ + private void buildWearableOnlyNotification(String title, String content, + boolean withDismissal) { + Notification.Builder builder = new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_launcher) + .setContentTitle(title) + .setContentText(content); + + if (withDismissal) { + Intent dismissIntent = new Intent(Constants.ACTION_DISMISS); + dismissIntent.putExtra(Constants.KEY_NOTIFICATION_ID, Constants.BOTH_ID); + PendingIntent pendingIntent = PendingIntent + .getService(this, 0, dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setDeleteIntent(pendingIntent); + } + + ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)) + .notify(Constants.WATCH_ONLY_ID, builder.build()); + } + + @Override + public void onConnected(Bundle bundle) { + final Uri dataItemUri = + new Uri.Builder().scheme(WEAR_URI_SCHEME).path(Constants.BOTH_PATH).build(); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Deleting Uri: " + dataItemUri.toString()); + } + Wearable.DataApi.deleteDataItems( + mGoogleApiClient, dataItemUri).setResultCallback(this); + } + + @Override + public void onConnectionSuspended(int i) { + } + + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + } + + @Override + public void onResult(DataApi.DeleteDataItemsResult deleteDataItemsResult) { + if (!deleteDataItemsResult.getStatus().isSuccess()) { + Log.e(TAG, "dismissWearableNotification(): failed to delete DataItem"); + } + mGoogleApiClient.disconnect(); + } +}
\ No newline at end of file diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/WearableActivity.java b/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/WearableActivity.java new file mode 100644 index 000000000..9c653d9b2 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/java/com/example/android/wearable/synchronizednotifications/WearableActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.wearable.synchronizednotifications; + +import android.app.Activity; +import android.os.Bundle; + +public class WearableActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_wearable); + } +} diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-hdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..f7dd9a0bd --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-mdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..fef2da78f --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..f2fb03cdd --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/layout/activity_wearable.xml b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/layout/activity_wearable.xml new file mode 100644 index 000000000..09a5887ce --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/layout/activity_wearable.xml @@ -0,0 +1,7 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".WearableActivity"> + +</RelativeLayout> diff --git a/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/values/strings.xml b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/values/strings.xml new file mode 100644 index 000000000..1627d19c8 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/Wearable/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Synchronized Notifications</string> + +</resources> diff --git a/samples/wearable/SynchronizedNotifications/build.gradle b/samples/wearable/SynchronizedNotifications/build.gradle new file mode 100644 index 000000000..8bd4ffc49 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/build.gradle @@ -0,0 +1,14 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.+' + } +} + +allprojects { + repositories { + mavenCentral() + } +} diff --git a/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.jar b/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 000000000..8c0fb64a8 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.jar diff --git a/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties b/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..1e61d1fd3 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/samples/wearable/SynchronizedNotifications/gradlew b/samples/wearable/SynchronizedNotifications/gradlew new file mode 100755 index 000000000..91a7e269e --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/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/SynchronizedNotifications/gradlew.bat b/samples/wearable/SynchronizedNotifications/gradlew.bat new file mode 100644 index 000000000..aec99730b --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/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/SynchronizedNotifications/settings.gradle b/samples/wearable/SynchronizedNotifications/settings.gradle new file mode 100644 index 000000000..7a1e93702 --- /dev/null +++ b/samples/wearable/SynchronizedNotifications/settings.gradle @@ -0,0 +1 @@ +include ':Application', ':Wearable', ':Common' diff --git a/samples/wearable/build.gradle b/samples/wearable/build.gradle index 643f04414..0b711431a 100644 --- a/samples/wearable/build.gradle +++ b/samples/wearable/build.gradle @@ -22,6 +22,7 @@ List<String> samples = [ "Quiz", "RecipeAssistant", "SkeletonWearableApp", + "SynchronizedNotifications", "Timer", "WatchViewStub", ] |
