Home | History | Annotate | Download | only in agendadata
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.wearable.agendadata;
     18 
     19 import android.app.Notification;
     20 import android.app.NotificationManager;
     21 import android.app.PendingIntent;
     22 import android.content.Intent;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapFactory;
     25 import android.net.Uri;
     26 import android.text.TextUtils;
     27 import android.text.format.DateFormat;
     28 import android.util.Log;
     29 
     30 import static com.example.android.wearable.agendadata.Constants.ALL_DAY;
     31 import static com.example.android.wearable.agendadata.Constants.BEGIN;
     32 import static com.example.android.wearable.agendadata.Constants.DESCRIPTION;
     33 import static com.example.android.wearable.agendadata.Constants.EXTRA_SILENT;
     34 import static com.example.android.wearable.agendadata.Constants.END;
     35 import static com.example.android.wearable.agendadata.Constants.PROFILE_PIC;
     36 import static com.example.android.wearable.agendadata.Constants.TAG;
     37 import static com.example.android.wearable.agendadata.Constants.TITLE;
     38 
     39 import com.google.android.gms.common.api.GoogleApiClient;
     40 import com.google.android.gms.wearable.Asset;
     41 import com.google.android.gms.wearable.DataApi;
     42 import com.google.android.gms.wearable.DataEvent;
     43 import com.google.android.gms.wearable.DataEventBuffer;
     44 import com.google.android.gms.wearable.DataItem;
     45 import com.google.android.gms.wearable.DataMap;
     46 import com.google.android.gms.wearable.DataMapItem;
     47 import com.google.android.gms.wearable.Wearable;
     48 import com.google.android.gms.wearable.WearableListenerService;
     49 
     50 import java.util.Date;
     51 import java.util.HashMap;
     52 import java.util.Map;
     53 
     54 /**
     55  * Listens to DataItem events on the home device.
     56  */
     57 public class HomeListenerService extends WearableListenerService {
     58 
     59     private static final Map<Uri, Integer> sNotificationIdByDataItemUri =
     60             new HashMap<Uri, Integer>();
     61     private static int sNotificationId = 1;
     62     private GoogleApiClient mGoogleApiClient;
     63 
     64     @Override
     65     public void onCreate() {
     66         super.onCreate();
     67         mGoogleApiClient = new GoogleApiClient.Builder(this.getApplicationContext())
     68                 .addApi(Wearable.API)
     69                 .build();
     70         mGoogleApiClient.connect();
     71     }
     72 
     73     @Override
     74     public void onDataChanged(DataEventBuffer dataEvents) {
     75         if (Log.isLoggable(TAG, Log.DEBUG)) {
     76             Log.d(TAG, "onDataChanged: " + dataEvents + " for " + getPackageName());
     77         }
     78         for (DataEvent event : dataEvents) {
     79 
     80             if (event.getType() == DataEvent.TYPE_DELETED) {
     81                 deleteDataItem(event.getDataItem());
     82             } else if (event.getType() == DataEvent.TYPE_CHANGED) {
     83                 updateNotificationForDataItem(event.getDataItem());
     84             }
     85         }
     86     }
     87 
     88     /**
     89      * Deletes the calendar card associated with the data item.
     90      */
     91     private void deleteDataItem(DataItem dataItem) {
     92         if (Log.isLoggable(TAG, Log.VERBOSE)) {
     93             Log.v(TAG, "onDataItemDeleted:DataItem=" + dataItem.getUri());
     94         }
     95         Integer notificationId = sNotificationIdByDataItemUri.remove(dataItem.getUri());
     96         if (notificationId != null) {
     97             ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(notificationId);
     98         }
     99     }
    100 
    101     /**
    102      * Posts a local notification to show calendar card.
    103      */
    104     private void updateNotificationForDataItem(DataItem dataItem) {
    105         DataMapItem mapDataItem = DataMapItem.fromDataItem(dataItem);
    106         DataMap data = mapDataItem.getDataMap();
    107 
    108         String description = data.getString(DESCRIPTION);
    109         if (TextUtils.isEmpty(description)) {
    110             description = "";
    111         } else {
    112             // Add a space between the description and the time of the event.
    113             description += " ";
    114         }
    115         String contentText;
    116         if (data.getBoolean(ALL_DAY)) {
    117             contentText = getString(R.string.desc_all_day, description);
    118         } else {
    119             String startTime = DateFormat.getTimeFormat(this).format(new Date(data.getLong(BEGIN)));
    120             String endTime = DateFormat.getTimeFormat(this).format(new Date(data.getLong(END)));
    121             contentText = getString(R.string.desc_time_period, description, startTime, endTime);
    122         }
    123 
    124         Intent deleteOperation = new Intent(this, DeleteService.class);
    125         // Use a unique identifier for the delete action.
    126         String deleteAction = "action_delete" + dataItem.getUri().toString() + sNotificationId;
    127         deleteOperation.setAction(deleteAction);
    128         deleteOperation.setData(dataItem.getUri());
    129         PendingIntent deleteIntent = PendingIntent.getService(this, 0, deleteOperation,
    130                 PendingIntent.FLAG_ONE_SHOT);
    131         PendingIntent silentDeleteIntent = PendingIntent.getService(this, 1,
    132                 deleteOperation.putExtra(EXTRA_SILENT, true), PendingIntent.FLAG_ONE_SHOT);
    133 
    134         Notification.Builder notificationBuilder = new Notification.Builder(this)
    135                 .setContentTitle(data.getString(TITLE))
    136                 .setContentText(contentText)
    137                 .setSmallIcon(R.drawable.ic_launcher)
    138                 .addAction(R.drawable.ic_menu_delete, getText(R.string.delete), deleteIntent)
    139                 .setDeleteIntent(silentDeleteIntent)  // Delete DataItem if notification dismissed.
    140                 .setLocalOnly(true)
    141                 .setPriority(Notification.PRIORITY_MIN);
    142 
    143         // Set the event owner's profile picture as the notification background.
    144         Asset asset = data.getAsset(PROFILE_PIC);
    145         if (null != asset) {
    146             if (mGoogleApiClient.isConnected()) {
    147                 DataApi.GetFdForAssetResult assetFdResult =
    148                         Wearable.DataApi.getFdForAsset(mGoogleApiClient, asset).await();
    149                 if (assetFdResult.getStatus().isSuccess()) {
    150                     Bitmap profilePic = BitmapFactory.decodeStream(assetFdResult.getInputStream());
    151                     notificationBuilder.extend(new Notification.WearableExtender()
    152                             .setBackground(profilePic));
    153                 } else if (Log.isLoggable(TAG, Log.DEBUG)) {
    154                     Log.d(TAG, "asset fetch failed with statusCode: "
    155                             + assetFdResult.getStatus().getStatusCode());
    156                 }
    157             } else {
    158                 Log.e(TAG, "Failed to set notification background"
    159                          + " - Client disconnected from Google Play Services");
    160             }
    161         }
    162         Notification card = notificationBuilder.build();
    163 
    164         ((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
    165                 .notify(sNotificationId, card);
    166 
    167         sNotificationIdByDataItemUri.put(dataItem.getUri(), sNotificationId++);
    168     }
    169 }
    170