Skip to content

Most visited

Recently visited

navigation
WearVerifyRemoteApp / Wearable / src / com.example.android.wearable.wear.wearverifyremoteapp /

MainWearActivity.java

1
/*
2
 * Copyright (C) 2016 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
package com.example.android.wearable.wear.wearverifyremoteapp;
17
 
18
import android.content.Intent;
19
import android.net.Uri;
20
import android.os.Bundle;
21
import android.os.Handler;
22
import android.os.ResultReceiver;
23
import android.support.annotation.NonNull;
24
import android.support.annotation.Nullable;
25
import android.support.wearable.activity.WearableActivity;
26
import android.support.wearable.view.ConfirmationOverlay;
27
import android.util.Log;
28
import android.view.View;
29
import android.widget.Button;
30
import android.widget.TextView;
31
 
32
import com.google.android.gms.common.ConnectionResult;
33
import com.google.android.gms.common.api.GoogleApiClient;
34
import com.google.android.gms.common.api.PendingResult;
35
import com.google.android.gms.common.api.ResultCallback;
36
import com.google.android.gms.wearable.CapabilityApi;
37
import com.google.android.gms.wearable.CapabilityInfo;
38
import com.google.android.gms.wearable.Node;
39
import com.google.android.gms.wearable.Wearable;
40
import com.google.android.wearable.intent.RemoteIntent;
41
import com.google.android.wearable.playstore.PlayStoreAvailability;
42
 
43
import java.util.Set;
44
 
45
/**
46
 * Checks if the phone app is installed on remote device. If it is not, allows user to open app
47
 * listing on the phone's Play or App Store.
48
 */
49
public class MainWearActivity extends WearableActivity implements
50
        GoogleApiClient.ConnectionCallbacks,
51
        GoogleApiClient.OnConnectionFailedListener,
52
        CapabilityApi.CapabilityListener {
53
 
54
    private static final String TAG = "MainWearActivity";
55
 
56
    private static final String WELCOME_MESSAGE = "Welcome to our Wear app!\n\n";
57
 
58
    private static final String CHECKING_MESSAGE =
59
            WELCOME_MESSAGE + "Checking for Mobile app...\n";
60
 
61
    private static final String MISSING_MESSAGE =
62
            WELCOME_MESSAGE
63
                    + "You are missing the required phone app, please click on the button below to "
64
                    + "install it on your phone.\n";
65
 
66
    private static final String INSTALLED_MESSAGE =
67
            WELCOME_MESSAGE
68
                    + "Mobile app installed on your %s!\n\nYou can now use MessageApi, "
69
                    + "DataApi, etc.";
70
 
71
    // Name of capability listed in Phone app's wear.xml.
72
    // IMPORTANT NOTE: This should be named differently than your Wear app's capability.
73
    private static final String CAPABILITY_PHONE_APP = "verify_remote_example_phone_app";
74
 
75
    // Links to install mobile app for both Android (Play Store) and iOS.
76
    // TODO: Replace with your links/packages.
77
    private static final String PLAY_STORE_APP_URI =
78
            "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp";
79
 
80
    // TODO: Replace with your links/packages.
81
    private static final String APP_STORE_APP_URI =
82
            "https://itunes.apple.com/us/app/android-wear/id986496028?mt=8";
83
 
84
    // Result from sending RemoteIntent to phone to open app in play/app store.
85
    private final ResultReceiver mResultReceiver = new ResultReceiver(new Handler()) {
86
        @Override
87
        protected void onReceiveResult(int resultCode, Bundle resultData) {
88
 
89
            if (resultCode == RemoteIntent.RESULT_OK) {
90
                new ConfirmationOverlay().showOn(MainWearActivity.this);
91
 
92
            } else if (resultCode == RemoteIntent.RESULT_FAILED) {
93
                new ConfirmationOverlay()
94
                        .setType(ConfirmationOverlay.FAILURE_ANIMATION)
95
                        .showOn(MainWearActivity.this);
96
 
97
            } else {
98
                throw new IllegalStateException("Unexpected result " + resultCode);
99
            }
100
        }
101
    };
102
 
103
    private TextView mInformationTextView;
104
    private Button mRemoteOpenButton;
105
 
106
    private Node mAndroidPhoneNodeWithApp;
107
 
108
    private GoogleApiClient mGoogleApiClient;
109
 
110
    @Override
111
    protected void onCreate(Bundle savedInstanceState) {
112
        Log.d(TAG, "onCreate()");
113
        super.onCreate(savedInstanceState);
114
 
115
        setContentView(R.layout.activity_main);
116
        setAmbientEnabled();
117
 
118
        mInformationTextView = (TextView) findViewById(R.id.information_text_view);
119
        mRemoteOpenButton = (Button) findViewById(R.id.remote_open_button);
120
 
121
        mInformationTextView.setText(CHECKING_MESSAGE);
122
 
123
        mRemoteOpenButton.setOnClickListener(new View.OnClickListener() {
124
            @Override
125
            public void onClick(View view) {
126
                openAppInStoreOnPhone();
127
            }
128
        });
129
 
130
        mGoogleApiClient = new GoogleApiClient.Builder(this)
131
                .addApi(Wearable.API)
132
                .addConnectionCallbacks(this)
133
                .addOnConnectionFailedListener(this)
134
                .build();
135
    }
136
 
137
 
138
    @Override
139
    protected void onPause() {
140
        Log.d(TAG, "onPause()");
141
        super.onPause();
142
 
143
        if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
144
            Wearable.CapabilityApi.removeCapabilityListener(
145
                    mGoogleApiClient,
146
                    this,
147
                    CAPABILITY_PHONE_APP);
148
 
149
            mGoogleApiClient.disconnect();
150
        }
151
    }
152
 
153
    @Override
154
    protected void onResume() {
155
        Log.d(TAG, "onResume()");
156
        super.onResume();
157
        if (mGoogleApiClient != null) {
158
            mGoogleApiClient.connect();
159
        }
160
    }
161
 
162
    @Override
163
    public void onConnected(@Nullable Bundle bundle) {
164
        Log.d(TAG, "onConnected()");
165
 
166
        // Set up listeners for capability changes (install/uninstall of remote app).
167
        Wearable.CapabilityApi.addCapabilityListener(
168
                mGoogleApiClient,
169
                this,
170
                CAPABILITY_PHONE_APP);
171
 
172
        checkIfPhoneHasApp();
173
    }
174
 
175
    @Override
176
    public void onConnectionSuspended(int i) {
177
        Log.d(TAG, "onConnectionSuspended(): connection to location client suspended: " + i);
178
    }
179
 
180
    @Override
181
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
182
        Log.e(TAG, "onConnectionFailed(): " + connectionResult);
183
    }
184
 
185
    /*
186
     * Updates UI when capabilities change (install/uninstall phone app).
187
     */
188
    public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
189
        Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo);
190
 
191
        mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes());
192
        verifyNodeAndUpdateUI();
193
    }
194
 
195
    private void checkIfPhoneHasApp() {
196
        Log.d(TAG, "checkIfPhoneHasApp()");
197
 
198
        PendingResult<CapabilityApi.GetCapabilityResult> pendingResult =
199
                Wearable.CapabilityApi.getCapability(
200
                        mGoogleApiClient,
201
                        CAPABILITY_PHONE_APP,
202
                        CapabilityApi.FILTER_ALL);
203
 
204
        pendingResult.setResultCallback(new ResultCallback<CapabilityApi.GetCapabilityResult>() {
205
 
206
            @Override
207
            public void onResult(@NonNull CapabilityApi.GetCapabilityResult getCapabilityResult) {
208
                Log.d(TAG, "onResult(): " + getCapabilityResult);
209
 
210
                if (getCapabilityResult.getStatus().isSuccess()) {
211
                    CapabilityInfo capabilityInfo = getCapabilityResult.getCapability();
212
                    mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes());
213
                    verifyNodeAndUpdateUI();
214
 
215
                } else {
216
                    Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus());
217
                }
218
            }
219
        });
220
    }
221
 
222
    private void verifyNodeAndUpdateUI() {
223
 
224
        if (mAndroidPhoneNodeWithApp != null) {
225
 
226
            // TODO: Add your code to communicate with the phone app via
227
            // Wear APIs (MessageApi, DataApi, etc.)
228
 
229
            String installMessage =
230
                    String.format(INSTALLED_MESSAGE, mAndroidPhoneNodeWithApp.getDisplayName());
231
            Log.d(TAG, installMessage);
232
            mInformationTextView.setText(installMessage);
233
            mRemoteOpenButton.setVisibility(View.INVISIBLE);
234
 
235
        } else {
236
            Log.d(TAG, MISSING_MESSAGE);
237
            mInformationTextView.setText(MISSING_MESSAGE);
238
            mRemoteOpenButton.setVisibility(View.VISIBLE);
239
        }
240
    }
241
 
242
    private void openAppInStoreOnPhone() {
243
        Log.d(TAG, "openAppInStoreOnPhone()");
244
 
245
        int playStoreAvailabilityOnPhone =
246
                PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(getApplicationContext());
247
 
248
        switch (playStoreAvailabilityOnPhone) {
249
 
250
            // Android phone with the Play Store.
251
            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE:
252
                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_AVAILABLE");
253
 
254
                // Create Remote Intent to open Play Store listing of app on remote device.
255
                Intent intentAndroid =
256
                        new Intent(Intent.ACTION_VIEW)
257
                                .addCategory(Intent.CATEGORY_BROWSABLE)
258
                                .setData(Uri.parse(PLAY_STORE_APP_URI));
259
 
260
                RemoteIntent.startRemoteActivity(
261
                        getApplicationContext(),
262
                        intentAndroid,
263
                        mResultReceiver);
264
                break;
265
 
266
            // Assume iPhone (iOS device) or Android without Play Store (not supported right now).
267
            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_UNAVAILABLE:
268
                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_UNAVAILABLE");
269
 
270
                // Create Remote Intent to open App Store listing of app on iPhone.
271
                Intent intentIOS =
272
                        new Intent(Intent.ACTION_VIEW)
273
                                .addCategory(Intent.CATEGORY_BROWSABLE)
274
                                .setData(Uri.parse(APP_STORE_APP_URI));
275
 
276
                RemoteIntent.startRemoteActivity(
277
                        getApplicationContext(),
278
                        intentIOS,
279
                        mResultReceiver);
280
                break;
281
 
282
            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_ERROR_UNKNOWN:
283
                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_ERROR_UNKNOWN");
284
                break;
285
        }
286
    }
287
 
288
    /*
289
     * There should only ever be one phone in a node set (much less w/ the correct capability), so
290
     * I am just grabbing the first one (which should be the only one).
291
     */
292
    private Node pickBestNodeId(Set<Node> nodes) {
293
        Log.d(TAG, "pickBestNodeId(): " + nodes);
294
 
295
        Node bestNodeId = null;
296
        // Find a nearby node/phone or pick one arbitrarily. Realistically, there is only one phone.
297
        for (Node node : nodes) {
298
            bestNodeId = node;
299
        }
300
        return bestNodeId;
301
    }
302
}