/* * 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.PendingIntent; import android.content.Intent; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.util.Log; import android.view.MenuItem; 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.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * A simple fragment 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 SynchronizedNotificationsFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static final String TAG = "SynchronizedFragment"; private GoogleApiClient mGoogleApiClient; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGoogleApiClient = new GoogleApiClient.Builder(this.getActivity()) .addApi(Wearable.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); setHasOptionsMenu(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.btn_phone_only: buildLocalOnlyNotification(getString(R.string.phone_only), now(), Constants.PHONE_ONLY_ID, false); return true; case R.id.btn_wear_only: buildWearableOnlyNotification(getString(R.string.wear_only), now(), Constants.WATCH_ONLY_PATH); return true; case R.id.btn_different: buildMirroredNotifications( getString(R.string.phone_both), getString(R.string.watch_both), now()); return true; } return false; } /** * 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.getActivity()); 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.getActivity(), 0, dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.setDeleteIntent(pendingIntent); } NotificationManagerCompat.from(this.getActivity()).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(); request.setUrgent(); 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 public void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override public 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() { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); return sdf.format(new Date()); } }