| /* | |
| * 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()); | |
| } | |
| } |