Home | History | Annotate | Download | only in findphone
      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.findphone;
     18 
     19 import android.app.Notification;
     20 import android.app.NotificationManager;
     21 import android.os.Bundle;
     22 import android.util.Log;
     23 
     24 import com.google.android.gms.common.api.GoogleApiClient;
     25 import com.google.android.gms.common.api.ResultCallback;
     26 import com.google.android.gms.wearable.CapabilityApi;
     27 import com.google.android.gms.wearable.CapabilityInfo;
     28 import com.google.android.gms.wearable.Node;
     29 import com.google.android.gms.wearable.Wearable;
     30 import com.google.android.gms.wearable.WearableListenerService;
     31 
     32 import java.util.List;
     33 import java.util.Set;
     34 
     35 /**
     36  * Listens for changes in connectivity between this wear device and the phone. More precisely, we
     37  * need to distinguish the case that the wear device and the phone are connected directly from all
     38  * other possible cases. To this end, the phone app has registered itself to provide the "find_me"
     39  * capability and we need to look for connected nodes that provide this capability AND are nearby,
     40  * to exclude a connection through the cloud. The proper way would have been to use the
     41  * {@code onCapabilitiesChanged()} callback but currently that callback cannot discover the case
     42  * where a connection switches from wifi to direct; this shortcoming will be addressed in future
     43  * updates but for now we will use the {@code onConnectedNodes()} callback.
     44  */
     45 public class DisconnectListenerService extends WearableListenerService
     46         implements GoogleApiClient.ConnectionCallbacks {
     47 
     48     private static final String TAG = "ExampleFindPhoneApp";
     49 
     50     private static final int FORGOT_PHONE_NOTIFICATION_ID = 1;
     51 
     52     /* the capability that the phone app would provide */
     53     private static final String FIND_ME_CAPABILITY_NAME = "find_me";
     54 
     55     private GoogleApiClient mGoogleApiClient;
     56 
     57     @Override
     58     public void onCreate() {
     59         super.onCreate();
     60         mGoogleApiClient = new GoogleApiClient.Builder(this)
     61                 .addApi(Wearable.API)
     62                 .addConnectionCallbacks(this)
     63                 .build();
     64     }
     65 
     66     @Override
     67     public void onConnectedNodes(List<Node> connectedNodes) {
     68         // After we are notified by this callback, we need to query for the nodes that provide the
     69         // "find_me" capability and are directly connected.
     70         if (mGoogleApiClient.isConnected()) {
     71             setOrUpdateNotification();
     72         } else if (!mGoogleApiClient.isConnecting()) {
     73             mGoogleApiClient.connect();
     74         }
     75     }
     76 
     77     private void setOrUpdateNotification() {
     78         Wearable.CapabilityApi.getCapability(
     79                 mGoogleApiClient, FIND_ME_CAPABILITY_NAME,
     80                 CapabilityApi.FILTER_REACHABLE).setResultCallback(
     81                 new ResultCallback<CapabilityApi.GetCapabilityResult>() {
     82                     @Override
     83                     public void onResult(CapabilityApi.GetCapabilityResult result) {
     84                         if (result.getStatus().isSuccess()) {
     85                             updateFindMeCapability(result.getCapability());
     86                         } else {
     87                             Log.e(TAG,
     88                                     "setOrUpdateNotification() Failed to get capabilities, "
     89                                             + "status: "
     90                                             + result.getStatus().getStatusMessage());
     91                         }
     92                     }
     93                 });
     94     }
     95 
     96     private void updateFindMeCapability(CapabilityInfo capabilityInfo) {
     97         Set<Node> connectedNodes = capabilityInfo.getNodes();
     98         if (connectedNodes.isEmpty()) {
     99             setupLostConnectivityNotification();
    100         } else {
    101             for (Node node : connectedNodes) {
    102                 // we are only considering those nodes that are directly connected
    103                 if (node.isNearby()) {
    104                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
    105                             .cancel(FORGOT_PHONE_NOTIFICATION_ID);
    106                 }
    107             }
    108         }
    109     }
    110 
    111     /**
    112      * Creates a notification to inform user that the connectivity to phone has been lost (possibly
    113      * left the phone behind).
    114      */
    115     private void setupLostConnectivityNotification() {
    116         Notification.Builder notificationBuilder = new Notification.Builder(this)
    117                 .setContentTitle(getString(R.string.left_phone_title))
    118                 .setContentText(getString(R.string.left_phone_content))
    119                 .setVibrate(new long[]{0, 200})  // Vibrate for 200 milliseconds.
    120                 .setSmallIcon(R.drawable.ic_launcher)
    121                 .setLocalOnly(true)
    122                 .setPriority(Notification.PRIORITY_MAX);
    123         Notification card = notificationBuilder.build();
    124         ((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
    125                 .notify(FORGOT_PHONE_NOTIFICATION_ID, card);
    126     }
    127 
    128     @Override
    129     public void onConnected(Bundle bundle) {
    130         setOrUpdateNotification();
    131     }
    132 
    133     @Override
    134     public void onConnectionSuspended(int cause) {
    135 
    136     }
    137 
    138     @Override
    139     public void onDestroy() {
    140         if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting()) {
    141             mGoogleApiClient.disconnect();
    142         }
    143         super.onDestroy();
    144     }
    145 }
    146