| /* |
| * Copyright (C) 2016 Google Inc. All Rights Reserved. |
| * |
| * 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.wear.wearverifyremoteapp; |
| |
| import android.content.Intent; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.ResultReceiver; |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.support.wearable.activity.WearableActivity; |
| import android.support.wearable.view.ConfirmationOverlay; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.Button; |
| import android.widget.TextView; |
| |
| import com.google.android.gms.common.ConnectionResult; |
| import com.google.android.gms.common.api.GoogleApiClient; |
| import com.google.android.gms.common.api.PendingResult; |
| import com.google.android.gms.common.api.ResultCallback; |
| import com.google.android.gms.wearable.CapabilityApi; |
| import com.google.android.gms.wearable.CapabilityInfo; |
| import com.google.android.gms.wearable.Node; |
| import com.google.android.gms.wearable.Wearable; |
| import com.google.android.wearable.intent.RemoteIntent; |
| import com.google.android.wearable.playstore.PlayStoreAvailability; |
| |
| import java.util.Set; |
| |
| /** |
| * Checks if the phone app is installed on remote device. If it is not, allows user to open app |
| * listing on the phone's Play or App Store. |
| */ |
| public class MainWearActivity extends WearableActivity implements |
| GoogleApiClient.ConnectionCallbacks, |
| GoogleApiClient.OnConnectionFailedListener, |
| CapabilityApi.CapabilityListener { |
| |
| private static final String TAG = "MainWearActivity"; |
| |
| private static final String WELCOME_MESSAGE = "Welcome to our Wear app!\n\n"; |
| |
| private static final String CHECKING_MESSAGE = |
| WELCOME_MESSAGE + "Checking for Mobile app...\n"; |
| |
| private static final String MISSING_MESSAGE = |
| WELCOME_MESSAGE |
| + "You are missing the required phone app, please click on the button below to " |
| + "install it on your phone.\n"; |
| |
| private static final String INSTALLED_MESSAGE = |
| WELCOME_MESSAGE |
| + "Mobile app installed on your %s!\n\nYou can now use MessageApi, " |
| + "DataApi, etc."; |
| |
| // Name of capability listed in Phone app's wear.xml. |
| // IMPORTANT NOTE: This should be named differently than your Wear app's capability. |
| private static final String CAPABILITY_PHONE_APP = "verify_remote_example_phone_app"; |
| |
| // Links to install mobile app for both Android (Play Store) and iOS. |
| // TODO: Replace with your links/packages. |
| private static final String PLAY_STORE_APP_URI = |
| "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp"; |
| |
| // TODO: Replace with your links/packages. |
| private static final String APP_STORE_APP_URI = |
| "https://itunes.apple.com/us/app/android-wear/id986496028?mt=8"; |
| |
| // Result from sending RemoteIntent to phone to open app in play/app store. |
| private final ResultReceiver mResultReceiver = new ResultReceiver(new Handler()) { |
| @Override |
| protected void onReceiveResult(int resultCode, Bundle resultData) { |
| |
| if (resultCode == RemoteIntent.RESULT_OK) { |
| new ConfirmationOverlay().showOn(MainWearActivity.this); |
| |
| } else if (resultCode == RemoteIntent.RESULT_FAILED) { |
| new ConfirmationOverlay() |
| .setType(ConfirmationOverlay.FAILURE_ANIMATION) |
| .showOn(MainWearActivity.this); |
| |
| } else { |
| throw new IllegalStateException("Unexpected result " + resultCode); |
| } |
| } |
| }; |
| |
| private TextView mInformationTextView; |
| private Button mRemoteOpenButton; |
| |
| private Node mAndroidPhoneNodeWithApp; |
| |
| private GoogleApiClient mGoogleApiClient; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| Log.d(TAG, "onCreate()"); |
| super.onCreate(savedInstanceState); |
| |
| setContentView(R.layout.activity_main); |
| setAmbientEnabled(); |
| |
| mInformationTextView = (TextView) findViewById(R.id.information_text_view); |
| mRemoteOpenButton = (Button) findViewById(R.id.remote_open_button); |
| |
| mInformationTextView.setText(CHECKING_MESSAGE); |
| |
| mRemoteOpenButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View view) { |
| openAppInStoreOnPhone(); |
| } |
| }); |
| |
| mGoogleApiClient = new GoogleApiClient.Builder(this) |
| .addApi(Wearable.API) |
| .addConnectionCallbacks(this) |
| .addOnConnectionFailedListener(this) |
| .build(); |
| } |
| |
| |
| @Override |
| protected void onPause() { |
| Log.d(TAG, "onPause()"); |
| super.onPause(); |
| |
| if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) { |
| Wearable.CapabilityApi.removeCapabilityListener( |
| mGoogleApiClient, |
| this, |
| CAPABILITY_PHONE_APP); |
| |
| mGoogleApiClient.disconnect(); |
| } |
| } |
| |
| @Override |
| protected void onResume() { |
| Log.d(TAG, "onResume()"); |
| super.onResume(); |
| if (mGoogleApiClient != null) { |
| mGoogleApiClient.connect(); |
| } |
| } |
| |
| @Override |
| public void onConnected(@Nullable Bundle bundle) { |
| Log.d(TAG, "onConnected()"); |
| |
| // Set up listeners for capability changes (install/uninstall of remote app). |
| Wearable.CapabilityApi.addCapabilityListener( |
| mGoogleApiClient, |
| this, |
| CAPABILITY_PHONE_APP); |
| |
| checkIfPhoneHasApp(); |
| } |
| |
| @Override |
| public void onConnectionSuspended(int i) { |
| Log.d(TAG, "onConnectionSuspended(): connection to location client suspended: " + i); |
| } |
| |
| @Override |
| public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { |
| Log.e(TAG, "onConnectionFailed(): " + connectionResult); |
| } |
| |
| /* |
| * Updates UI when capabilities change (install/uninstall phone app). |
| */ |
| public void onCapabilityChanged(CapabilityInfo capabilityInfo) { |
| Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo); |
| |
| mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes()); |
| verifyNodeAndUpdateUI(); |
| } |
| |
| private void checkIfPhoneHasApp() { |
| Log.d(TAG, "checkIfPhoneHasApp()"); |
| |
| PendingResult<CapabilityApi.GetCapabilityResult> pendingResult = |
| Wearable.CapabilityApi.getCapability( |
| mGoogleApiClient, |
| CAPABILITY_PHONE_APP, |
| CapabilityApi.FILTER_ALL); |
| |
| pendingResult.setResultCallback(new ResultCallback<CapabilityApi.GetCapabilityResult>() { |
| |
| @Override |
| public void onResult(@NonNull CapabilityApi.GetCapabilityResult getCapabilityResult) { |
| Log.d(TAG, "onResult(): " + getCapabilityResult); |
| |
| if (getCapabilityResult.getStatus().isSuccess()) { |
| CapabilityInfo capabilityInfo = getCapabilityResult.getCapability(); |
| mAndroidPhoneNodeWithApp = pickBestNodeId(capabilityInfo.getNodes()); |
| verifyNodeAndUpdateUI(); |
| |
| } else { |
| Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus()); |
| } |
| } |
| }); |
| } |
| |
| private void verifyNodeAndUpdateUI() { |
| |
| if (mAndroidPhoneNodeWithApp != null) { |
| |
| // TODO: Add your code to communicate with the phone app via |
| // Wear APIs (MessageApi, DataApi, etc.) |
| |
| String installMessage = |
| String.format(INSTALLED_MESSAGE, mAndroidPhoneNodeWithApp.getDisplayName()); |
| Log.d(TAG, installMessage); |
| mInformationTextView.setText(installMessage); |
| mRemoteOpenButton.setVisibility(View.INVISIBLE); |
| |
| } else { |
| Log.d(TAG, MISSING_MESSAGE); |
| mInformationTextView.setText(MISSING_MESSAGE); |
| mRemoteOpenButton.setVisibility(View.VISIBLE); |
| } |
| } |
| |
| private void openAppInStoreOnPhone() { |
| Log.d(TAG, "openAppInStoreOnPhone()"); |
| |
| int playStoreAvailabilityOnPhone = |
| PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(getApplicationContext()); |
| |
| switch (playStoreAvailabilityOnPhone) { |
| |
| // Android phone with the Play Store. |
| case PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE: |
| Log.d(TAG, "\tPLAY_STORE_ON_PHONE_AVAILABLE"); |
| |
| // Create Remote Intent to open Play Store listing of app on remote device. |
| Intent intentAndroid = |
| new Intent(Intent.ACTION_VIEW) |
| .addCategory(Intent.CATEGORY_BROWSABLE) |
| .setData(Uri.parse(PLAY_STORE_APP_URI)); |
| |
| RemoteIntent.startRemoteActivity( |
| getApplicationContext(), |
| intentAndroid, |
| mResultReceiver); |
| break; |
| |
| // Assume iPhone (iOS device) or Android without Play Store (not supported right now). |
| case PlayStoreAvailability.PLAY_STORE_ON_PHONE_UNAVAILABLE: |
| Log.d(TAG, "\tPLAY_STORE_ON_PHONE_UNAVAILABLE"); |
| |
| // Create Remote Intent to open App Store listing of app on iPhone. |
| Intent intentIOS = |
| new Intent(Intent.ACTION_VIEW) |
| .addCategory(Intent.CATEGORY_BROWSABLE) |
| .setData(Uri.parse(APP_STORE_APP_URI)); |
| |
| RemoteIntent.startRemoteActivity( |
| getApplicationContext(), |
| intentIOS, |
| mResultReceiver); |
| break; |
| |
| case PlayStoreAvailability.PLAY_STORE_ON_PHONE_ERROR_UNKNOWN: |
| Log.d(TAG, "\tPLAY_STORE_ON_PHONE_ERROR_UNKNOWN"); |
| break; |
| } |
| } |
| |
| /* |
| * There should only ever be one phone in a node set (much less w/ the correct capability), so |
| * I am just grabbing the first one (which should be the only one). |
| */ |
| private Node pickBestNodeId(Set<Node> nodes) { |
| Log.d(TAG, "pickBestNodeId(): " + nodes); |
| |
| Node bestNodeId = null; |
| // Find a nearby node/phone or pick one arbitrarily. Realistically, there is only one phone. |
| for (Node node : nodes) { |
| bestNodeId = node; |
| } |
| return bestNodeId; |
| } |
| } |