/* * 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.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; 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.NodeApi; import com.google.android.gms.wearable.Wearable; import com.google.android.wearable.intent.RemoteIntent; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * Checks if the sample's Wear app is installed on remote Wear device(s). If it is not, allows the * user to open the app listing on the Wear devices' Play Store. */ public class MainMobileActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, CapabilityApi.CapabilityListener { private static final String TAG = "MainMobileActivity"; private static final String WELCOME_MESSAGE = "Welcome to our Mobile app!\n\n"; private static final String CHECKING_MESSAGE = WELCOME_MESSAGE + "Checking for Wear Devices for app...\n"; private static final String NO_DEVICES = WELCOME_MESSAGE + "You have no Wear devices linked to your phone at this time.\n"; private static final String MISSING_ALL_MESSAGE = WELCOME_MESSAGE + "You are missing the Wear app on all your Wear Devices, please click on the " + "button below to install it on those device(s).\n"; private static final String INSTALLED_SOME_DEVICES_MESSAGE = WELCOME_MESSAGE + "Wear app installed on some your device(s) (%s)!\n\nYou can now use the " + "MessageApi, DataApi, etc.\n\n" + "To install the Wear app on the other devices, please click on the button " + "below.\n"; private static final String INSTALLED_ALL_DEVICES_MESSAGE = WELCOME_MESSAGE + "Wear app installed on all your devices (%s)!\n\nYou can now use the " + "MessageApi, DataApi, etc."; // Name of capability listed in Wear app's wear.xml. // IMPORTANT NOTE: This should be named differently than your Phone app's capability. private static final String CAPABILITY_WEAR_APP = "verify_remote_example_wear_app"; // Links to Wear app (Play Store). // TODO: Replace with your links/packages. private static final String PLAY_STORE_APP_URI = "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp"; // Result from sending RemoteIntent to wear device(s) to open app in play/app store. private final ResultReceiver mResultReceiver = new ResultReceiver(new Handler()) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { Log.d(TAG, "onReceiveResult: " + resultCode); if (resultCode == RemoteIntent.RESULT_OK) { Toast toast = Toast.makeText( getApplicationContext(), "Play Store Request to Wear device successful.", Toast.LENGTH_SHORT); toast.show(); } else if (resultCode == RemoteIntent.RESULT_FAILED) { Toast toast = Toast.makeText( getApplicationContext(), "Play Store Request Failed. Wear device(s) may not support Play Store, " + " that is, the Wear device may be version 1.0.", Toast.LENGTH_LONG); toast.show(); } else { throw new IllegalStateException("Unexpected result " + resultCode); } } }; private TextView mInformationTextView; private Button mRemoteOpenButton; private Set mWearNodesWithApp; private List mAllConnectedNodes; private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate()"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 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 v) { openPlayStoreOnWearDevicesWithoutApp(); } }); 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_WEAR_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_WEAR_APP); // Initial request for devices with our capability, aka, our Wear app installed. findWearDevicesWithApp(); // Initial request for all Wear devices connected (with or without our capability). // Additional Note: Because there isn't a listener for ALL Nodes added/removed from network // that isn't deprecated, we simply update the full list when the Google API Client is // connected and when capability changes come through in the onCapabilityChanged() method. findAllWearDevices(); } @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 wear app). */ public void onCapabilityChanged(CapabilityInfo capabilityInfo) { Log.d(TAG, "onCapabilityChanged(): " + capabilityInfo); mWearNodesWithApp = capabilityInfo.getNodes(); // Because we have an updated list of devices with/without our app, we need to also update // our list of active Wear devices. findAllWearDevices(); verifyNodeAndUpdateUI(); } private void findWearDevicesWithApp() { Log.d(TAG, "findWearDevicesWithApp()"); // You can filter this by FILTER_REACHABLE if you only want to open Nodes (Wear Devices) // directly connect to your phone. PendingResult pendingResult = Wearable.CapabilityApi.getCapability( mGoogleApiClient, CAPABILITY_WEAR_APP, CapabilityApi.FILTER_ALL); pendingResult.setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull CapabilityApi.GetCapabilityResult getCapabilityResult) { Log.d(TAG, "onResult(): " + getCapabilityResult); if (getCapabilityResult.getStatus().isSuccess()) { CapabilityInfo capabilityInfo = getCapabilityResult.getCapability(); mWearNodesWithApp = capabilityInfo.getNodes(); verifyNodeAndUpdateUI(); } else { Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus()); } } }); } private void findAllWearDevices() { Log.d(TAG, "findAllWearDevices()"); PendingResult pendingResult = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient); pendingResult.setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull NodeApi.GetConnectedNodesResult getConnectedNodesResult) { if (getConnectedNodesResult.getStatus().isSuccess()) { mAllConnectedNodes = getConnectedNodesResult.getNodes(); verifyNodeAndUpdateUI(); } else { Log.d(TAG, "Failed CapabilityApi: " + getConnectedNodesResult.getStatus()); } } }); } private void verifyNodeAndUpdateUI() { Log.d(TAG, "verifyNodeAndUpdateUI()"); if ((mWearNodesWithApp == null) || (mAllConnectedNodes == null)) { Log.d(TAG, "Waiting on Results for both connected nodes and nodes with app"); } else if (mAllConnectedNodes.isEmpty()) { Log.d(TAG, NO_DEVICES); mInformationTextView.setText(NO_DEVICES); mRemoteOpenButton.setVisibility(View.INVISIBLE); } else if (mWearNodesWithApp.isEmpty()) { Log.d(TAG, MISSING_ALL_MESSAGE); mInformationTextView.setText(MISSING_ALL_MESSAGE); mRemoteOpenButton.setVisibility(View.VISIBLE); } else if (mWearNodesWithApp.size() < mAllConnectedNodes.size()) { // TODO: Add your code to communicate with the wear app(s) via // Wear APIs (MessageApi, DataApi, etc.) String installMessage = String.format(INSTALLED_SOME_DEVICES_MESSAGE, mWearNodesWithApp); Log.d(TAG, installMessage); mInformationTextView.setText(installMessage); mRemoteOpenButton.setVisibility(View.VISIBLE); } else { // TODO: Add your code to communicate with the wear app(s) via // Wear APIs (MessageApi, DataApi, etc.) String installMessage = String.format(INSTALLED_ALL_DEVICES_MESSAGE, mWearNodesWithApp); Log.d(TAG, installMessage); mInformationTextView.setText(installMessage); mRemoteOpenButton.setVisibility(View.INVISIBLE); } } private void openPlayStoreOnWearDevicesWithoutApp() { Log.d(TAG, "openPlayStoreOnWearDevicesWithoutApp()"); // Create a List of Nodes (Wear devices) without your app. ArrayList nodesWithoutApp = new ArrayList<>(); for (Node node : mAllConnectedNodes) { if (!mWearNodesWithApp.contains(node)) { nodesWithoutApp.add(node); } } if (!nodesWithoutApp.isEmpty()) { Log.d(TAG, "Number of nodes without app: " + nodesWithoutApp.size()); Intent intent = new Intent(Intent.ACTION_VIEW) .addCategory(Intent.CATEGORY_BROWSABLE) .setData(Uri.parse(PLAY_STORE_APP_URI)); for (Node node : nodesWithoutApp) { RemoteIntent.startRemoteActivity( getApplicationContext(), intent, mResultReceiver, node.getId()); } } } }