upload android base code part7

This commit is contained in:
August 2018-08-08 18:09:17 +08:00
parent 4e516ec6ed
commit 841ae54672
25229 changed files with 1709508 additions and 0 deletions

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.wearable.wear.wearverifyremoteapp"
android:versionCode="1"
android:versionName="1.0">
<application android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppThemeCustom">
<activity android:name=".MainMobileActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.android.wearable.wear.wearverifyremoteapp.MainMobileActivity">
<TextView
android:id="@+id/information_text_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"/>
<Button
android:id="@+id/remote_open_button"
android:layout_width="match_parent"
android:text="Install App on Wear device(s)"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible"/>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,24 @@
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<!-- Semantic definitions -->
<dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
</resources>

View file

@ -0,0 +1,25 @@
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<style name="Widget.SampleMessage">
<item name="android:textAppearance">?android:textAppearanceLarge</item>
<item name="android:lineSpacingMultiplier">1.2</item>
<item name="android:shadowDy">-6.5</item>
</style>
</resources>

View file

@ -0,0 +1,22 @@
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<!-- Activity themes -->
<style name="Theme.Base" parent="android:Theme.Holo.Light" />
</resources>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<!-- Activity themes -->
<style name="Theme.Base" parent="android:Theme.Material.Light">
</style>
</resources>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<string name="app_name">WearVerifyRemoteApp</string>
<string name="intro_message">
<![CDATA[
Sample demonstrates best practices for checking if the remote version of your app is installed on a
connected device. This enables standalone Android Wear apps to check if the phone app is installed
and the other way around.
]]>
</string>
</resources>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<!-- Base application theme. -->
<style name="AppThemeCustom" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View file

@ -0,0 +1,32 @@
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
<dimen name="margin_tiny">4dp</dimen>
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_medium">16dp</dimen>
<dimen name="margin_large">32dp</dimen>
<dimen name="margin_huge">64dp</dimen>
<!-- Semantic definitions -->
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
</resources>

View file

@ -0,0 +1,42 @@
<!--
Copyright 2013 The Android Open Source Project
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.
-->
<resources>
<!-- Activity themes -->
<style name="Theme.Base" parent="android:Theme.Light" />
<style name="Theme.Sample" parent="Theme.Base" />
<style name="AppTheme" parent="Theme.Sample" />
<!-- Widget styling -->
<style name="Widget" />
<style name="Widget.SampleMessage">
<item name="android:textAppearance">?android:textAppearanceMedium</item>
<item name="android:lineSpacingMultiplier">1.1</item>
</style>
<style name="Widget.SampleMessageTile">
<item name="android:background">@drawable/tile</item>
<item name="android:shadowColor">#7F000000</item>
<item name="android:shadowDy">-3.5</item>
<item name="android:shadowRadius">2</item>
</style>
</resources>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<string-array name="android_wear_capabilities">
<!-- IMPORTANT NOTE: Should be different than capability in Wear res/values/wear.xml. -->
<item>verify_remote_example_phone_app</item>
</string-array>
</resources>

View file

@ -0,0 +1,341 @@
/*
* 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<Node> mWearNodesWithApp;
private List<Node> 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<CapabilityApi.GetCapabilityResult> pendingResult =
Wearable.CapabilityApi.getCapability(
mGoogleApiClient,
CAPABILITY_WEAR_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();
mWearNodesWithApp = capabilityInfo.getNodes();
verifyNodeAndUpdateUI();
} else {
Log.d(TAG, "Failed CapabilityApi: " + getCapabilityResult.getStatus());
}
}
});
}
private void findAllWearDevices() {
Log.d(TAG, "findAllWearDevices()");
PendingResult<NodeApi.GetConnectedNodesResult> pendingResult =
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient);
pendingResult.setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@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<Node> 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());
}
}
}
}

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<manifest package="com.example.android.wearable.wear.wearverifyremoteapp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0">
<uses-feature android:name="android.hardware.type.watch"/>
<!-- Required for Always-on. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault">
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
<!--If you want your app to run on pre-22, then set required to false -->
<uses-library android:name="com.google.android.wearable" android:required="false" />
<activity
android:name=".MainWearActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/activity_main_top_padding"
android:paddingRight="@dimen/activity_main_right_padding"
android:paddingLeft="@dimen/activity_main_left_padding"
android:paddingBottom="@dimen/activity_main_bottom_padding"
tools:context="com.example.android.wearable.wear.wearverifyremoteapp.MainWearActivity">
<TextView
android:id="@+id/information_text_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"/>
<Button
android:id="@+id/remote_open_button"
android:layout_width="match_parent"
android:text="Install Mobile App"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible"/>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<dimen name="activity_main_top_padding">36dp</dimen>
<dimen name="activity_main_bottom_padding">22dp</dimen>
<dimen name="activity_main_right_padding">36dp</dimen>
<dimen name="activity_main_left_padding">36dp</dimen>
</resources>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<dimen name="activity_main_top_padding">5dp</dimen>
<dimen name="activity_main_bottom_padding">5dp</dimen>
<dimen name="activity_main_right_padding">5dp</dimen>
<dimen name="activity_main_left_padding">5dp</dimen>
</resources>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<string name="app_name">Wear Verify Remote App</string>
</resources>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Google Inc.
~
~ 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.
-->
<resources>
<string-array name="android_wear_capabilities">
<!-- IMPORTANT NOTE: Should be different than capability in App res/values/wear.xml. -->
<item>verify_remote_example_wear_app</item>
</string-array>
</resources>

View file

@ -0,0 +1,302 @@
/*
* 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;
}
}

View file

@ -0,0 +1,12 @@
page.tags="WearVerifyRemoteApp"
sample.group=Wearable
@jd:body
<p>
Sample demonstrates best practices for checking if the remote version of your app is installed on a
connected device. This enables standalone Android Wear apps to check if the phone app is installed
and the other way around.
</p>