Skip to content

Most visited

Recently visited

navigation
RuntimePermissionsWear / Wearable / src / com.example.android.wearable.runtimepermissions /

MainWearActivity.java

1
/*
2
 * Copyright (C) 2015 Google Inc. All Rights Reserved.
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.runtimepermissions;
18
 
19
import android.Manifest;
20
import android.content.Intent;
21
import android.content.pm.PackageManager;
22
import android.hardware.Sensor;
23
import android.hardware.SensorManager;
24
import android.os.Bundle;
25
import android.os.Looper;
26
import android.support.annotation.NonNull;
27
import android.support.v4.app.ActivityCompat;
28
import android.support.wearable.activity.WearableActivity;
29
import android.support.wearable.view.WatchViewStub;
30
import android.util.Log;
31
import android.view.View;
32
import android.widget.Button;
33
import android.widget.TextView;
34
 
35
import com.example.android.wearable.runtimepermissions.common.Constants;
36
 
37
import com.google.android.gms.common.ConnectionResult;
38
import com.google.android.gms.common.api.GoogleApiClient;
39
import com.google.android.gms.common.api.PendingResult;
40
import com.google.android.gms.common.api.ResultCallback;
41
import com.google.android.gms.wearable.CapabilityApi;
42
import com.google.android.gms.wearable.CapabilityInfo;
43
import com.google.android.gms.wearable.DataMap;
44
import com.google.android.gms.wearable.MessageApi;
45
import com.google.android.gms.wearable.MessageEvent;
46
import com.google.android.gms.wearable.Node;
47
import com.google.android.gms.wearable.Wearable;
48
 
49
import java.util.List;
50
import java.util.Set;
51
import java.util.concurrent.TimeUnit;
52
 
53
/**
54
 * Displays data that requires runtime permissions both locally (BODY_SENSORS) and remotely on
55
 * the phone (READ_EXTERNAL_STORAGE).
56
 *
57
 * The class is also launched by IncomingRequestWearService when the permission for the data the
58
 * phone is trying to access hasn't been granted (wear's sensors). If granted in that scenario,
59
 * this Activity also sends back the results of the permission request to the phone device (and
60
 * the sensor data if approved).
61
 */
62
public class MainWearActivity extends WearableActivity implements
63
        GoogleApiClient.ConnectionCallbacks,
64
        GoogleApiClient.OnConnectionFailedListener,
65
        CapabilityApi.CapabilityListener,
66
        MessageApi.MessageListener,
67
        ActivityCompat.OnRequestPermissionsResultCallback {
68
 
69
    private static final String TAG = "MainWearActivity";
70
 
71
    /* Id to identify local permission request for body sensors. */
72
    private static final int PERMISSION_REQUEST_READ_BODY_SENSORS = 1;
73
 
74
    /* Id to identify starting/closing RequestPermissionOnPhoneActivity (startActivityForResult). */
75
    private static final int REQUEST_PHONE_PERMISSION = 1;
76
 
77
    public static final String EXTRA_PROMPT_PERMISSION_FROM_PHONE =
78
            "com.example.android.wearable.runtimepermissions.extra.PROMPT_PERMISSION_FROM_PHONE";
79
 
80
    private boolean mWearBodySensorsPermissionApproved;
81
    private boolean mPhoneStoragePermissionApproved;
82
 
83
    private boolean mPhoneRequestingWearSensorPermission;
84
 
85
    private Button mWearBodySensorsPermissionButton;
86
    private Button mPhoneStoragePermissionButton;
87
    private TextView mOutputTextView;
88
 
89
    private String mPhoneNodeId;
90
 
91
    private GoogleApiClient mGoogleApiClient;
92
 
93
    @Override
94
    protected void onCreate(Bundle savedInstanceState) {
95
        Log.d(TAG, "onCreate()");
96
        super.onCreate(savedInstanceState);;
97
 
98
        /*
99
         * Since this is a remote permission, we initialize it to false and then check the remote
100
         * permission once the GoogleApiClient is connected.
101
         */
102
        mPhoneStoragePermissionApproved = false;
103
 
104
        setContentView(R.layout.activity_main);
105
        setAmbientEnabled();
106
 
107
        // Checks if phone app requested wear permission (permission request opens later if true).
108
        mPhoneRequestingWearSensorPermission =
109
                getIntent().getBooleanExtra(EXTRA_PROMPT_PERMISSION_FROM_PHONE, false);
110
 
111
        final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
112
        stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
113
            @Override
114
            public void onLayoutInflated(WatchViewStub stub) {
115
 
116
                mWearBodySensorsPermissionButton =
117
                        (Button) stub.findViewById(R.id.wearBodySensorsPermissionButton);
118
 
119
                if (mWearBodySensorsPermissionApproved) {
120
                    mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
121
                            R.drawable.ic_permission_approved, 0, 0, 0);
122
                }
123
 
124
                mPhoneStoragePermissionButton =
125
                        (Button) stub.findViewById(R.id.phoneStoragePermissionButton);
126
 
127
                mOutputTextView = (TextView) stub.findViewById(R.id.output);
128
 
129
                if (mPhoneRequestingWearSensorPermission) {
130
                    launchPermissionDialogForPhone();
131
                }
132
 
133
            }
134
        });
135
 
136
        mGoogleApiClient = new GoogleApiClient.Builder(this)
137
                .addApi(Wearable.API)
138
                .addConnectionCallbacks(this)
139
                .addOnConnectionFailedListener(this)
140
                .build();
141
    }
142
 
143
    public void onClickWearBodySensors(View view) {
144
 
145
        if (mWearBodySensorsPermissionApproved) {
146
 
147
            // To keep the sample simple, we are only displaying the number of sensors.
148
            SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
149
            List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
150
            int numberOfSensorsOnDevice = sensorList.size();
151
 
152
            logToUi(numberOfSensorsOnDevice + " sensors on device(s)!");
153
 
154
        } else {
155
            logToUi("Requested local permission.");
156
            // On 23+ (M+) devices, GPS permission not granted. Request permission.
157
            ActivityCompat.requestPermissions(
158
                    this,
159
                    new String[]{Manifest.permission.BODY_SENSORS},
160
                    PERMISSION_REQUEST_READ_BODY_SENSORS);
161
        }
162
    }
163
 
164
    public void onClickPhoneStorage(View view) {
165
 
166
        logToUi("Requested info from phone. New approval may be required.");
167
        DataMap dataMap = new DataMap();
168
        dataMap.putInt(Constants.KEY_COMM_TYPE,
169
                Constants.COMM_TYPE_REQUEST_DATA);
170
        sendMessage(dataMap);
171
    }
172
 
173
    @Override
174
    protected void onPause() {
175
        Log.d(TAG, "onPause()");
176
        super.onPause();
177
        if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
178
            Wearable.CapabilityApi.removeCapabilityListener(
179
                    mGoogleApiClient,
180
                    this,
181
                    Constants.CAPABILITY_PHONE_APP);
182
            Wearable.MessageApi.removeListener(mGoogleApiClient, this);
183
            mGoogleApiClient.disconnect();
184
        }
185
    }
186
 
187
    @Override
188
    protected void onResume() {
189
        Log.d(TAG, "onResume()");
190
        super.onResume();
191
        if (mGoogleApiClient != null) {
192
            mGoogleApiClient.connect();
193
        }
194
 
195
        // Enables app to handle 23+ (M+) style permissions.
196
        mWearBodySensorsPermissionApproved =
197
                ActivityCompat.checkSelfPermission(this, Manifest.permission.BODY_SENSORS)
198
                        == PackageManager.PERMISSION_GRANTED;
199
    }
200
 
201
     /*
202
      * Because this wear activity is marked "android:launchMode='singleInstance'" in the manifest,
203
      * we need to allow the permissions dialog to be opened up from the phone even if the wear app
204
      * is in the foreground. By overriding onNewIntent, we can cover that use case.
205
      */
206
    @Override
207
    protected void onNewIntent (Intent intent) {
208
        Log.d(TAG, "onNewIntent()");
209
        super.onNewIntent(intent);
210
 
211
        // Checks if phone app requested wear permissions (opens up permission request if true).
212
        mPhoneRequestingWearSensorPermission =
213
                intent.getBooleanExtra(EXTRA_PROMPT_PERMISSION_FROM_PHONE, false);
214
 
215
        if (mPhoneRequestingWearSensorPermission) {
216
            launchPermissionDialogForPhone();
217
        }
218
    }
219
 
220
    @Override
221
    public void onEnterAmbient(Bundle ambientDetails) {
222
        Log.d(TAG, "onEnterAmbient() " + ambientDetails);
223
 
224
        if (mWearBodySensorsPermissionApproved) {
225
            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
226
                    R.drawable.ic_permission_approved_bw, 0, 0, 0);
227
        } else {
228
            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
229
                    R.drawable.ic_permission_denied_bw, 0, 0, 0);
230
        }
231
 
232
        if (mPhoneStoragePermissionApproved) {
233
            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
234
                    R.drawable.ic_permission_approved_bw, 0, 0, 0);
235
        } else {
236
            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
237
                    R.drawable.ic_permission_denied_bw, 0, 0, 0);
238
        }
239
        super.onEnterAmbient(ambientDetails);
240
    }
241
 
242
    @Override
243
    public void onExitAmbient() {
244
        Log.d(TAG, "onExitAmbient()");
245
 
246
        if (mWearBodySensorsPermissionApproved) {
247
            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
248
                    R.drawable.ic_permission_approved, 0, 0, 0);
249
        } else {
250
            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
251
                    R.drawable.ic_permission_denied, 0, 0, 0);
252
        }
253
 
254
        if (mPhoneStoragePermissionApproved) {
255
            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
256
                    R.drawable.ic_permission_approved, 0, 0, 0);
257
        } else {
258
            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
259
                    R.drawable.ic_permission_denied, 0, 0, 0);
260
        }
261
        super.onExitAmbient();
262
    }
263
 
264
    @Override
265
    public void onConnected(Bundle bundle) {
266
        Log.d(TAG, "onConnected()");
267
 
268
        // Set up listeners for capability and message changes.
269
        Wearable.CapabilityApi.addCapabilityListener(
270
                mGoogleApiClient,
271
                this,
272
                Constants.CAPABILITY_PHONE_APP);
273
        Wearable.MessageApi.addListener(mGoogleApiClient, this);
274
 
275
        // Initial check of capabilities to find the phone.
276
        PendingResult<CapabilityApi.GetCapabilityResult> pendingResult =
277
                Wearable.CapabilityApi.getCapability(
278
                        mGoogleApiClient,
279
                        Constants.CAPABILITY_PHONE_APP,
280
                        CapabilityApi.FILTER_REACHABLE);
281
 
282
        pendingResult.setResultCallback(new ResultCallback<CapabilityApi.GetCapabilityResult>() {
283
            @Override
284
            public void onResult(CapabilityApi.GetCapabilityResult getCapabilityResult) {
285
 
286
                if (getCapabilityResult.getStatus().isSuccess()) {
287
                    CapabilityInfo capabilityInfo = getCapabilityResult.getCapability();
288
                    mPhoneNodeId = pickBestNodeId(capabilityInfo.getNodes());
289
 
290
                } else {
291
                    Log.d(TAG, "Failed CapabilityApi result: "
292
                            + getCapabilityResult.getStatus());
293
                }
294
            }
295
        });
296
    }
297
 
298
    @Override
299
    public void onConnectionSuspended(int i) {
300
        Log.d(TAG, "onConnectionSuspended(): connection to location client suspended");
301
    }
302
 
303
    @Override
304
    public void onConnectionFailed(ConnectionResult connectionResult) {
305
        Log.e(TAG, "onConnectionFailed(): connection to location client failed");
306
    }
307
 
308
    public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
309
        Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo);
310
 
311
        mPhoneNodeId = pickBestNodeId(capabilityInfo.getNodes());
312
    }
313
 
314
    /*
315
     * Callback received when a permissions request has been completed.
316
     */
317
    @Override
318
    public void onRequestPermissi