Sync sample prebuilts to lmp-mr1-ub-docs
Upstream commit: f76d10f3b6abad250d94b5b9a5c73faae6ce8cc5 Change-Id: I32f2690e36f444cae123134268472fb526c26163
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.datalayer" >
|
package="com.example.android.wearable.datalayer" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="18"
|
<uses-sdk android:minSdkVersion="18"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
|
|
||||||
|
|||||||
23
samples/browseable/DataLayer/Application/res/values/wear.xml
Normal file
23
samples/browseable/DataLayer/Application/res/values/wear.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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-array name="android_wear_capabilities" translatable="false">
|
||||||
|
<!-- declaring the provided capabilities -->
|
||||||
|
<item>capability_1</item>
|
||||||
|
<item>capability_2</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
@@ -37,18 +37,18 @@ import android.widget.ListView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.ResultCallback;
|
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
|
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
|
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
|
||||||
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
import com.google.android.gms.common.data.FreezableUtils;
|
import com.google.android.gms.common.data.FreezableUtils;
|
||||||
import com.google.android.gms.wearable.Asset;
|
import com.google.android.gms.wearable.Asset;
|
||||||
|
import com.google.android.gms.wearable.DataApi;
|
||||||
import com.google.android.gms.wearable.DataApi.DataItemResult;
|
import com.google.android.gms.wearable.DataApi.DataItemResult;
|
||||||
import com.google.android.gms.wearable.DataEvent;
|
import com.google.android.gms.wearable.DataEvent;
|
||||||
import com.google.android.gms.wearable.DataEventBuffer;
|
import com.google.android.gms.wearable.DataEventBuffer;
|
||||||
import com.google.android.gms.wearable.MessageApi.SendMessageResult;
|
|
||||||
import com.google.android.gms.wearable.DataApi;
|
|
||||||
import com.google.android.gms.wearable.MessageApi;
|
import com.google.android.gms.wearable.MessageApi;
|
||||||
|
import com.google.android.gms.wearable.MessageApi.SendMessageResult;
|
||||||
import com.google.android.gms.wearable.MessageEvent;
|
import com.google.android.gms.wearable.MessageEvent;
|
||||||
import com.google.android.gms.wearable.Node;
|
import com.google.android.gms.wearable.Node;
|
||||||
import com.google.android.gms.wearable.NodeApi;
|
import com.google.android.gms.wearable.NodeApi;
|
||||||
@@ -69,8 +69,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives its own events using a listener API designed for foreground activities. Updates a data
|
* Receives its own events using a listener API designed for foreground activities. Updates a data
|
||||||
* item every second while it is open. Also allows user to take a photo and send that as an asset to
|
* item every second while it is open. Also allows user to take a photo and send that as an asset
|
||||||
* the paired wearable.
|
* to the paired wearable.
|
||||||
*/
|
*/
|
||||||
public class MainActivity extends Activity implements DataApi.DataListener,
|
public class MainActivity extends Activity implements DataApi.DataListener,
|
||||||
MessageApi.MessageListener, NodeApi.NodeListener, ConnectionCallbacks,
|
MessageApi.MessageListener, NodeApi.NodeListener, ConnectionCallbacks,
|
||||||
@@ -78,7 +78,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
|
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
|
|
||||||
/** Request code for launching the Intent to resolve Google Play services errors. */
|
/**
|
||||||
|
* Request code for launching the Intent to resolve Google Play services errors.
|
||||||
|
*/
|
||||||
private static final int REQUEST_RESOLVE_ERROR = 1000;
|
private static final int REQUEST_RESOLVE_ERROR = 1000;
|
||||||
|
|
||||||
private static final String START_ACTIVITY_PATH = "/start-activity";
|
private static final String START_ACTIVITY_PATH = "/start-activity";
|
||||||
@@ -92,7 +94,6 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
private boolean mCameraSupported = false;
|
private boolean mCameraSupported = false;
|
||||||
|
|
||||||
private ListView mDataItemList;
|
private ListView mDataItemList;
|
||||||
private Button mTakePhotoBtn;
|
|
||||||
private Button mSendPhotoBtn;
|
private Button mSendPhotoBtn;
|
||||||
private ImageView mThumbView;
|
private ImageView mThumbView;
|
||||||
private Bitmap mImageBitmap;
|
private Bitmap mImageBitmap;
|
||||||
@@ -320,7 +321,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Collection<String> getNodes() {
|
private Collection<String> getNodes() {
|
||||||
HashSet<String> results = new HashSet<String>();
|
HashSet<String> results = new HashSet<>();
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
|
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
|
||||||
|
|
||||||
@@ -358,7 +359,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends an RPC to start a fullscreen Activity on the wearable. */
|
/**
|
||||||
|
* Sends an RPC to start a fullscreen Activity on the wearable.
|
||||||
|
*/
|
||||||
public void onStartWearableActivityClick(View view) {
|
public void onStartWearableActivityClick(View view) {
|
||||||
LOGD(TAG, "Generating RPC");
|
LOGD(TAG, "Generating RPC");
|
||||||
|
|
||||||
@@ -367,7 +370,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
new StartWearableActivityTask().execute();
|
new StartWearableActivityTask().execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generates a DataItem based on an incrementing count. */
|
/**
|
||||||
|
* Generates a DataItem based on an incrementing count.
|
||||||
|
*/
|
||||||
private class DataItemGenerator implements Runnable {
|
private class DataItemGenerator implements Runnable {
|
||||||
|
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
@@ -462,13 +467,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
* Sets up UI components and their callback handlers.
|
* Sets up UI components and their callback handlers.
|
||||||
*/
|
*/
|
||||||
private void setupViews() {
|
private void setupViews() {
|
||||||
mTakePhotoBtn = (Button) findViewById(R.id.takePhoto);
|
|
||||||
mSendPhotoBtn = (Button) findViewById(R.id.sendPhoto);
|
mSendPhotoBtn = (Button) findViewById(R.id.sendPhoto);
|
||||||
|
|
||||||
// Shows the image received from the handset
|
|
||||||
mThumbView = (ImageView) findViewById(R.id.imageView);
|
mThumbView = (ImageView) findViewById(R.id.imageView);
|
||||||
mDataItemList = (ListView) findViewById(R.id.data_item_list);
|
mDataItemList = (ListView) findViewById(R.id.data_item_list);
|
||||||
|
|
||||||
mStartActivityBtn = findViewById(R.id.start_wearable_activity);
|
mStartActivityBtn = findViewById(R.id.start_wearable_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.datalayer" >
|
package="com.example.android.wearable.datalayer" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="20"
|
<uses-sdk android:minSdkVersion="20"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.type.watch" />
|
<uses-feature android:name="android.hardware.type.watch" />
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<corners android:radius="20dp"/>
|
||||||
|
<padding android:left="10dp" android:right="10dp" android:top="5dp" android:bottom="5dp"/>
|
||||||
|
<solid android:color="@color/black"/>
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/layout"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/photo"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/photo_placeholder"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/layout"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="@color/black">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/dataItem_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:transcriptMode="alwaysScroll"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/intro"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:fontFamily="sans-serif-condensed-light"
|
||||||
|
android:text="@string/intro" />
|
||||||
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:id="@+id/center"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:layout_centerVertical="true" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/capability_2_btn"
|
||||||
|
android:text="@string/capability_2_notification"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_above="@id/center"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:onClick="onClicked" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/capabilities_1_and_2_btn"
|
||||||
|
android:text="@string/capabilities_1_and_2_notification"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/center"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:layout_alignEnd="@+id/capability_2_btn"
|
||||||
|
android:layout_alignStart="@+id/capability_2_btn"
|
||||||
|
android:onClick="onClicked" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -15,25 +15,24 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/layout"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="fill_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="fill_parent">
|
android:background="@color/white">
|
||||||
|
|
||||||
<ListView
|
<android.support.wearable.view.GridViewPager
|
||||||
android:id="@+id/dataItem_list"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:transcriptMode="alwaysScroll"/>
|
|
||||||
|
|
||||||
<TextView
|
<android.support.wearable.view.DotsPageIndicator
|
||||||
android:id="@+id/intro"
|
android:id="@+id/page_indicator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:textSize="20sp"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginLeft="16dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_marginRight="16dp"
|
android:padding="5dp"
|
||||||
android:gravity="center"
|
android:background="@drawable/rounded_background">
|
||||||
android:fontFamily="sans-serif-condensed-light"
|
</android.support.wearable.view.DotsPageIndicator>
|
||||||
android:text="@string/intro" />
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
19
samples/browseable/DataLayer/Wearable/res/values/dimens.xml
Normal file
19
samples/browseable/DataLayer/Wearable/res/values/dimens.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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>
|
||||||
|
<dimen name="dots_spacing">15dp</dimen>
|
||||||
|
</resources>
|
||||||
@@ -17,4 +17,8 @@
|
|||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="app_name">Data Layer Sample Wearable App</string>
|
<string name="app_name">Data Layer Sample Wearable App</string>
|
||||||
<string name="intro">Waiting for data to arrive\u2026</string>
|
<string name="intro">Waiting for data to arrive\u2026</string>
|
||||||
|
<string name="capability_2_notification">Capability 2</string>
|
||||||
|
<string name="capabilities_1_and_2_notification">Capabilities 1 and 2</string>
|
||||||
|
<string name="no_device">No device provides the requested capabilities</string>
|
||||||
|
<string name="connected_nodes">Nodes: %1$s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
22
samples/browseable/DataLayer/Wearable/res/values/wear.xml
Normal file
22
samples/browseable/DataLayer/Wearable/res/values/wear.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2015 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-array name="android_wear_capabilities" translatable="false">
|
||||||
|
<!-- declaring the provided capabilities -->
|
||||||
|
<item>capability_1</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
@@ -45,8 +45,6 @@ public class DataLayerListenerService extends WearableListenerService {
|
|||||||
public static final String COUNT_PATH = "/count";
|
public static final String COUNT_PATH = "/count";
|
||||||
public static final String IMAGE_PATH = "/image";
|
public static final String IMAGE_PATH = "/image";
|
||||||
public static final String IMAGE_KEY = "photo";
|
public static final String IMAGE_KEY = "photo";
|
||||||
private static final String COUNT_KEY = "count";
|
|
||||||
private static final int MAX_LOG_TAG_LENGTH = 23;
|
|
||||||
GoogleApiClient mGoogleApiClient;
|
GoogleApiClient mGoogleApiClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,11 +61,12 @@ public class DataLayerListenerService extends WearableListenerService {
|
|||||||
LOGD(TAG, "onDataChanged: " + dataEvents);
|
LOGD(TAG, "onDataChanged: " + dataEvents);
|
||||||
final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);
|
final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);
|
||||||
dataEvents.close();
|
dataEvents.close();
|
||||||
if(!mGoogleApiClient.isConnected()) {
|
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting()) {
|
||||||
ConnectionResult connectionResult = mGoogleApiClient
|
ConnectionResult connectionResult = mGoogleApiClient
|
||||||
.blockingConnect(30, TimeUnit.SECONDS);
|
.blockingConnect(30, TimeUnit.SECONDS);
|
||||||
if (!connectionResult.isSuccess()) {
|
if (!connectionResult.isSuccess()) {
|
||||||
Log.e(TAG, "DataLayerListenerService failed to connect to GoogleApiClient.");
|
Log.e(TAG, "DataLayerListenerService failed to connect to GoogleApiClient, "
|
||||||
|
+ "error code: " + connectionResult.getErrorCode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,27 +19,33 @@ package com.example.android.wearable.datalayer;
|
|||||||
import static com.example.android.wearable.datalayer.DataLayerListenerService.LOGD;
|
import static com.example.android.wearable.datalayer.DataLayerListenerService.LOGD;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.app.Fragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.support.wearable.view.DotsPageIndicator;
|
||||||
|
import android.support.wearable.view.FragmentGridPagerAdapter;
|
||||||
|
import android.support.wearable.view.GridViewPager;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.Toast;
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
|
import com.example.android.wearable.datalayer.fragments.AssetFragment;
|
||||||
|
import com.example.android.wearable.datalayer.fragments.DataFragment;
|
||||||
|
import com.example.android.wearable.datalayer.fragments.DiscoveryFragment;
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
|
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
|
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
|
||||||
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
import com.google.android.gms.common.data.FreezableUtils;
|
import com.google.android.gms.common.data.FreezableUtils;
|
||||||
import com.google.android.gms.wearable.Asset;
|
import com.google.android.gms.wearable.Asset;
|
||||||
|
import com.google.android.gms.wearable.CapabilityApi;
|
||||||
|
import com.google.android.gms.wearable.CapabilityInfo;
|
||||||
import com.google.android.gms.wearable.DataApi;
|
import com.google.android.gms.wearable.DataApi;
|
||||||
import com.google.android.gms.wearable.DataEvent;
|
import com.google.android.gms.wearable.DataEvent;
|
||||||
import com.google.android.gms.wearable.DataEventBuffer;
|
import com.google.android.gms.wearable.DataEventBuffer;
|
||||||
@@ -51,39 +57,47 @@ import com.google.android.gms.wearable.NodeApi;
|
|||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows events and photo from the Wearable APIs.
|
* The main activity with a view pager, containing three pages:<p/>
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* Page 1: shows a list of DataItems received from the phone application
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Page 2: shows the photo that is sent from the phone application
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Page 3: includes two buttons to show the connected phone and watch devices
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class MainActivity extends Activity implements ConnectionCallbacks,
|
public class MainActivity extends Activity implements ConnectionCallbacks,
|
||||||
OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener,
|
OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener,
|
||||||
NodeApi.NodeListener {
|
NodeApi.NodeListener {
|
||||||
|
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
|
private static final String CAPABILITY_1_NAME = "capability_1";
|
||||||
|
private static final String CAPABILITY_2_NAME = "capability_2";
|
||||||
|
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient mGoogleApiClient;
|
||||||
private ListView mDataItemList;
|
|
||||||
private TextView mIntroText;
|
|
||||||
private DataItemAdapter mDataItemListAdapter;
|
|
||||||
private View mLayout;
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
private GridViewPager mPager;
|
||||||
|
private DataFragment mDataFragment;
|
||||||
|
private AssetFragment mAssetFragment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle b) {
|
public void onCreate(Bundle b) {
|
||||||
super.onCreate(b);
|
super.onCreate(b);
|
||||||
mHandler = new Handler();
|
mHandler = new Handler();
|
||||||
LOGD(TAG, "onCreate");
|
|
||||||
setContentView(R.layout.main_activity);
|
setContentView(R.layout.main_activity);
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
mDataItemList = (ListView) findViewById(R.id.dataItem_list);
|
setupViews();
|
||||||
mIntroText = (TextView) findViewById(R.id.intro);
|
|
||||||
mLayout = findViewById(R.id.layout);
|
|
||||||
|
|
||||||
// Stores data events received by the local broadcaster.
|
|
||||||
mDataItemListAdapter = new DataItemAdapter(this, android.R.layout.simple_list_item_1);
|
|
||||||
mDataItemList.setAdapter(mDataItemListAdapter);
|
|
||||||
|
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addApi(Wearable.API)
|
.addApi(Wearable.API)
|
||||||
.addConnectionCallbacks(this)
|
.addConnectionCallbacks(this)
|
||||||
@@ -128,8 +142,7 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mIntroText.setVisibility(View.INVISIBLE);
|
mDataFragment.appendItem(title, text);
|
||||||
mDataItemListAdapter.add(new Event(title, text));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -151,8 +164,9 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
|||||||
mHandler.post(new Runnable() {
|
mHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d(TAG, "Setting background image..");
|
Log.d(TAG, "Setting background image on second page..");
|
||||||
mLayout.setBackground(new BitmapDrawable(getResources(), bitmap));
|
moveToPage(1);
|
||||||
|
mAssetFragment.setBackgroundImage(bitmap);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -171,6 +185,70 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onClicked(View view) {
|
||||||
|
switch (view.getId()) {
|
||||||
|
case R.id.capability_2_btn:
|
||||||
|
showNodes(CAPABILITY_2_NAME);
|
||||||
|
break;
|
||||||
|
case R.id.capabilities_1_and_2_btn:
|
||||||
|
showNodes(CAPABILITY_1_NAME, CAPABILITY_2_NAME);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Unknown click event registered");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the connected nodes that provide at least one of the given capabilities
|
||||||
|
*/
|
||||||
|
private void showNodes(final String... capabilityNames) {
|
||||||
|
Wearable.CapabilityApi.getAllCapabilities(mGoogleApiClient,
|
||||||
|
CapabilityApi.FILTER_REACHABLE).setResultCallback(
|
||||||
|
|
||||||
|
new ResultCallback<CapabilityApi.GetAllCapabilitiesResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(
|
||||||
|
CapabilityApi.GetAllCapabilitiesResult getAllCapabilitiesResult) {
|
||||||
|
if (!getAllCapabilitiesResult.getStatus().isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed to get capabilities");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, CapabilityInfo>
|
||||||
|
capabilitiesMap = getAllCapabilitiesResult.getAllCapabilities();
|
||||||
|
Set<Node> nodes = new HashSet<>();
|
||||||
|
if (capabilitiesMap.isEmpty()) {
|
||||||
|
showDiscoveredNodes(nodes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String capabilityName : capabilityNames) {
|
||||||
|
CapabilityInfo capabilityInfo = capabilitiesMap.get(capabilityName);
|
||||||
|
if (capabilityInfo != null) {
|
||||||
|
nodes.addAll(capabilityInfo.getNodes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showDiscoveredNodes(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDiscoveredNodes(Set<Node> nodes) {
|
||||||
|
List<String> nodesList = new ArrayList<>();
|
||||||
|
for (Node node : nodes) {
|
||||||
|
nodesList.add(node.getDisplayName());
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Connected Nodes: " + (nodesList.isEmpty()
|
||||||
|
? "No connected device was found for the given capabilities"
|
||||||
|
: TextUtils.join(",", nodesList)));
|
||||||
|
String msg;
|
||||||
|
if (!nodesList.isEmpty()) {
|
||||||
|
msg = getString(R.string.connected_nodes,
|
||||||
|
TextUtils.join(", ", nodesList));
|
||||||
|
} else {
|
||||||
|
msg = getString(R.string.no_device);
|
||||||
|
}
|
||||||
|
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts {@link android.graphics.Bitmap} data from the
|
* Extracts {@link android.graphics.Bitmap} data from the
|
||||||
* {@link com.google.android.gms.wearable.Asset}
|
* {@link com.google.android.gms.wearable.Asset}
|
||||||
@@ -206,50 +284,53 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
|||||||
generateEvent("Node Disconnected", node.getId());
|
generateEvent("Node Disconnected", node.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DataItemAdapter extends ArrayAdapter<Event> {
|
private void setupViews() {
|
||||||
|
mPager = (GridViewPager) findViewById(R.id.pager);
|
||||||
|
mPager.setOffscreenPageCount(2);
|
||||||
|
DotsPageIndicator dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.page_indicator);
|
||||||
|
dotsPageIndicator.setDotSpacing((int) getResources().getDimension(R.dimen.dots_spacing));
|
||||||
|
dotsPageIndicator.setPager(mPager);
|
||||||
|
mDataFragment = new DataFragment();
|
||||||
|
mAssetFragment = new AssetFragment();
|
||||||
|
DiscoveryFragment discoveryFragment = new DiscoveryFragment();
|
||||||
|
List<Fragment> pages = new ArrayList<>();
|
||||||
|
pages.add(mDataFragment);
|
||||||
|
pages.add(mAssetFragment);
|
||||||
|
pages.add(discoveryFragment);
|
||||||
|
final MyPagerAdapter adapter = new MyPagerAdapter(getFragmentManager(), pages);
|
||||||
|
mPager.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
private final Context mContext;
|
/**
|
||||||
|
* Switches to the page {@code index}. The first page has index 0.
|
||||||
|
*/
|
||||||
|
private void moveToPage(int index) {
|
||||||
|
mPager.setCurrentItem(0, index, true);
|
||||||
|
}
|
||||||
|
|
||||||
public DataItemAdapter(Context context, int unusedResource) {
|
private class MyPagerAdapter extends FragmentGridPagerAdapter {
|
||||||
super(context, unusedResource);
|
|
||||||
mContext = context;
|
private List<Fragment> mFragments;
|
||||||
|
|
||||||
|
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
|
||||||
|
super(fm);
|
||||||
|
mFragments = fragments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public int getRowCount() {
|
||||||
ViewHolder holder;
|
return 1;
|
||||||
if (convertView == null) {
|
|
||||||
holder = new ViewHolder();
|
|
||||||
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
|
|
||||||
Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
convertView = inflater.inflate(android.R.layout.two_line_list_item, null);
|
|
||||||
convertView.setTag(holder);
|
|
||||||
holder.text1 = (TextView) convertView.findViewById(android.R.id.text1);
|
|
||||||
holder.text2 = (TextView) convertView.findViewById(android.R.id.text2);
|
|
||||||
} else {
|
|
||||||
holder = (ViewHolder) convertView.getTag();
|
|
||||||
}
|
|
||||||
Event event = getItem(position);
|
|
||||||
holder.text1.setText(event.title);
|
|
||||||
holder.text2.setText(event.text);
|
|
||||||
return convertView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ViewHolder {
|
@Override
|
||||||
|
public int getColumnCount(int row) {
|
||||||
TextView text1;
|
return mFragments == null ? 0 : mFragments.size();
|
||||||
TextView text2;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class Event {
|
@Override
|
||||||
|
public Fragment getFragment(int row, int column) {
|
||||||
String title;
|
return mFragments.get(column);
|
||||||
String text;
|
|
||||||
|
|
||||||
public Event(String title, String text) {
|
|
||||||
this.title = title;
|
|
||||||
this.text = text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.wearable.datalayer.fragments;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.example.android.wearable.datalayer.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple fragment that shows a (photo) asset received from the phone.
|
||||||
|
*/
|
||||||
|
public class AssetFragment extends Fragment {
|
||||||
|
|
||||||
|
private ImageView mPhoto;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.asset_fragment, container, false);
|
||||||
|
mPhoto = (ImageView) view.findViewById(R.id.photo);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackgroundImage(Bitmap bitmap) {
|
||||||
|
mPhoto.setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.wearable.datalayer.fragments;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.example.android.wearable.datalayer.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fragment that shows a list of DataItems received from the phone
|
||||||
|
*/
|
||||||
|
public class DataFragment extends Fragment {
|
||||||
|
|
||||||
|
private DataItemAdapter mDataItemListAdapter;
|
||||||
|
private TextView mIntroText;
|
||||||
|
private boolean mInitialized;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.data_fragment, container, false);
|
||||||
|
ListView dataItemList = (ListView) view.findViewById(R.id.dataItem_list);
|
||||||
|
mIntroText = (TextView) view.findViewById(R.id.intro);
|
||||||
|
mDataItemListAdapter = new DataItemAdapter(getActivity(),
|
||||||
|
android.R.layout.simple_list_item_1);
|
||||||
|
dataItemList.setAdapter(mDataItemListAdapter);
|
||||||
|
mInitialized = true;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendItem(String title, String text) {
|
||||||
|
if (!mInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIntroText.setVisibility(View.INVISIBLE);
|
||||||
|
mDataItemListAdapter.add(new Event(title, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DataItemAdapter extends ArrayAdapter<Event> {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public DataItemAdapter(Context context, int unusedResource) {
|
||||||
|
super(context, unusedResource);
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
ViewHolder holder;
|
||||||
|
if (convertView == null) {
|
||||||
|
holder = new ViewHolder();
|
||||||
|
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
|
||||||
|
Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflater.inflate(android.R.layout.two_line_list_item, null);
|
||||||
|
convertView.setTag(holder);
|
||||||
|
holder.text1 = (TextView) convertView.findViewById(android.R.id.text1);
|
||||||
|
holder.text2 = (TextView) convertView.findViewById(android.R.id.text2);
|
||||||
|
} else {
|
||||||
|
holder = (ViewHolder) convertView.getTag();
|
||||||
|
}
|
||||||
|
Event event = getItem(position);
|
||||||
|
holder.text1.setText(event.title);
|
||||||
|
holder.text2.setText(event.text);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder {
|
||||||
|
|
||||||
|
TextView text1;
|
||||||
|
TextView text2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Event {
|
||||||
|
|
||||||
|
String title;
|
||||||
|
String text;
|
||||||
|
|
||||||
|
public Event(String title, String text) {
|
||||||
|
this.title = title;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.wearable.datalayer.fragments;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.example.android.wearable.datalayer.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple fragment with two buttons to show connected phones and watches
|
||||||
|
*/
|
||||||
|
public class DiscoveryFragment extends Fragment {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.discovery_fragment, container, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.delayedconfirmation" >
|
package="com.example.android.wearable.delayedconfirmation" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="18"
|
<uses-sdk android:minSdkVersion="18"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities" translatable="false">
|
||||||
|
<!-- declaring that phone can handle confirmation messages -->
|
||||||
|
<item>confirmation_handler</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
@@ -109,15 +109,15 @@ public class MainActivity extends Activity implements MessageApi.MessageListener
|
|||||||
public void onStartWearableActivityClick(View view) {
|
public void onStartWearableActivityClick(View view) {
|
||||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
||||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
||||||
for (final Node node : getConnectedNodesResult.getNodes()) {
|
for (final Node node : getConnectedNodesResult.getNodes()) {
|
||||||
Wearable.MessageApi.sendMessage(
|
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(),
|
||||||
mGoogleApiClient, node.getId(), START_ACTIVITY_PATH, new byte[0])
|
START_ACTIVITY_PATH, new byte[0]).setResultCallback(
|
||||||
.setResultCallback(getSendMessageResultCallback());
|
getSendMessageResultCallback());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback() {
|
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback() {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.delayedconfirmation" >
|
package="com.example.android.wearable.delayedconfirmation" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="20"
|
<uses-sdk android:minSdkVersion="20"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.type.watch" />
|
<uses-feature android:name="android.hardware.type.watch" />
|
||||||
|
|
||||||
|
|||||||
@@ -22,4 +22,5 @@
|
|||||||
<string name="notification_title">DelayedConfirmation</string>
|
<string name="notification_title">DelayedConfirmation</string>
|
||||||
<string name="notification_timer_selected">Timer Selected</string>
|
<string name="notification_timer_selected">Timer Selected</string>
|
||||||
<string name="notification_timer_finished">Timer Finished</string>
|
<string name="notification_timer_finished">Timer Finished</string>
|
||||||
|
<string name="no_device_found">No device able to confirm was found</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -23,19 +23,23 @@ import android.os.Bundle;
|
|||||||
import android.support.wearable.view.DelayedConfirmationView;
|
import android.support.wearable.view.DelayedConfirmationView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
import com.google.android.gms.common.api.ResultCallback;
|
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.MessageApi;
|
import com.google.android.gms.wearable.MessageApi;
|
||||||
import com.google.android.gms.wearable.Node;
|
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.gms.wearable.Wearable;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class MainActivity extends Activity implements
|
public class MainActivity extends Activity implements
|
||||||
DelayedConfirmationView.DelayedConfirmationListener,
|
DelayedConfirmationView.DelayedConfirmationListener,
|
||||||
GoogleApiClient.OnConnectionFailedListener {
|
GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
|
||||||
|
CapabilityApi.CapabilityListener {
|
||||||
|
|
||||||
private static final String TAG = "DelayedConfirmation";
|
private static final String TAG = "DelayedConfirmation";
|
||||||
private static final int NUM_SECONDS = 5;
|
private static final int NUM_SECONDS = 5;
|
||||||
@@ -43,9 +47,15 @@ public class MainActivity extends Activity implements
|
|||||||
private static final String TIMER_SELECTED_PATH = "/timer_selected";
|
private static final String TIMER_SELECTED_PATH = "/timer_selected";
|
||||||
private static final String TIMER_FINISHED_PATH = "/timer_finished";
|
private static final String TIMER_FINISHED_PATH = "/timer_finished";
|
||||||
|
|
||||||
|
/* name of the capability that the phone side provides */
|
||||||
|
private static final String CONFIRMATION_HANDLER_CAPABILITY_NAME = "confirmation_handler";
|
||||||
|
|
||||||
private DelayedConfirmationView delayedConfirmationView;
|
private DelayedConfirmationView delayedConfirmationView;
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient mGoogleApiClient;
|
||||||
|
|
||||||
|
/* the preferred note that can handle the confirmation capability */
|
||||||
|
private Node mConfirmationHandlerNode;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle b) {
|
public void onCreate(Bundle b) {
|
||||||
super.onCreate(b);
|
super.onCreate(b);
|
||||||
@@ -55,6 +65,7 @@ public class MainActivity extends Activity implements
|
|||||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addApi(Wearable.API)
|
.addApi(Wearable.API)
|
||||||
.addOnConnectionFailedListener(this)
|
.addOnConnectionFailedListener(this)
|
||||||
|
.addConnectionCallbacks(this)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,11 +78,13 @@ public class MainActivity extends Activity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onPause() {
|
||||||
if (mGoogleApiClient.isConnected()) {
|
if (mGoogleApiClient.isConnected()) {
|
||||||
|
Wearable.CapabilityApi.removeCapabilityListener(mGoogleApiClient, this,
|
||||||
|
CONFIRMATION_HANDLER_CAPABILITY_NAME);
|
||||||
mGoogleApiClient.disconnect();
|
mGoogleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
super.onDestroy();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,32 +125,94 @@ public class MainActivity extends Activity implements
|
|||||||
@Override
|
@Override
|
||||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||||
Log.e(TAG, "Failed to connect to Google Api Client");
|
Log.e(TAG, "Failed to connect to Google Api Client");
|
||||||
|
mConfirmationHandlerNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessageToCompanion(final String path) {
|
private void sendMessageToCompanion(final String path) {
|
||||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
if (mConfirmationHandlerNode != null) {
|
||||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
Wearable.MessageApi.sendMessage(mGoogleApiClient, mConfirmationHandlerNode.getId(),
|
||||||
@Override
|
path, new byte[0])
|
||||||
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
.setResultCallback(getSendMessageResultCallback(mConfirmationHandlerNode));
|
||||||
for (final Node node : getConnectedNodesResult.getNodes()) {
|
} else {
|
||||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path,
|
Toast.makeText(this, R.string.no_device_found, Toast.LENGTH_SHORT).show();
|
||||||
new byte[0]).setResultCallback(getSendMessageResultCallback());
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback() {
|
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback(
|
||||||
|
final Node node) {
|
||||||
return new ResultCallback<MessageApi.SendMessageResult>() {
|
return new ResultCallback<MessageApi.SendMessageResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
|
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
|
||||||
if (!sendMessageResult.getStatus().isSuccess()) {
|
if (!sendMessageResult.getStatus().isSuccess()) {
|
||||||
Log.e(TAG, "Failed to connect to Google Api Client with status "
|
Log.e(TAG, "Failed to send message with status "
|
||||||
+ sendMessageResult.getStatus());
|
+ sendMessageResult.getStatus());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Sent confirmation message to node " + node.getDisplayName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupConfirmationHandlerNode() {
|
||||||
|
Wearable.CapabilityApi.addCapabilityListener(
|
||||||
|
mGoogleApiClient, this, CONFIRMATION_HANDLER_CAPABILITY_NAME);
|
||||||
|
|
||||||
|
Wearable.CapabilityApi.getCapability(
|
||||||
|
mGoogleApiClient, CONFIRMATION_HANDLER_CAPABILITY_NAME,
|
||||||
|
CapabilityApi.FILTER_REACHABLE).setResultCallback(
|
||||||
|
new ResultCallback<CapabilityApi.GetCapabilityResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(CapabilityApi.GetCapabilityResult result) {
|
||||||
|
if (!result.getStatus().isSuccess()) {
|
||||||
|
Log.e(TAG, "setupConfirmationHandlerNode() Failed to get capabilities, "
|
||||||
|
+ "status: " + result.getStatus().getStatusMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateConfirmationCapability(result.getCapability());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfirmationCapability(CapabilityInfo capabilityInfo) {
|
||||||
|
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||||
|
if (connectedNodes.isEmpty()) {
|
||||||
|
mConfirmationHandlerNode = null;
|
||||||
|
} else {
|
||||||
|
mConfirmationHandlerNode = pickBestNode(connectedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We pick a node that is capabale of handling the confirmation. If there is more than one,
|
||||||
|
* then we would prefer the one that is directly connected to this device. In general,
|
||||||
|
* depending on the situation and requirements, the "best" node might be picked based on other
|
||||||
|
* criteria.
|
||||||
|
*/
|
||||||
|
private Node pickBestNode(Set<Node> connectedNodes) {
|
||||||
|
Node best = null;
|
||||||
|
if (connectedNodes != null) {
|
||||||
|
for (Node node : connectedNodes) {
|
||||||
|
if (node.isNearby()) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
best = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnected(Bundle bundle) {
|
||||||
|
setupConfirmationHandlerNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionSuspended(int cause) {
|
||||||
|
mConfirmationHandlerNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
|
||||||
|
updateConfirmationCapability(capabilityInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.google.android.gms.wearable.WearableListenerService;
|
|||||||
* Listens for a message telling it to start the Wearable MainActivity.
|
* Listens for a message telling it to start the Wearable MainActivity.
|
||||||
*/
|
*/
|
||||||
public class WearableMessageListenerService extends WearableListenerService {
|
public class WearableMessageListenerService extends WearableListenerService {
|
||||||
|
|
||||||
private static final String START_ACTIVITY_PATH = "/start-activity";
|
private static final String START_ACTIVITY_PATH = "/start-activity";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.findphone">
|
package="com.example.android.wearable.findphone">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="18"
|
<uses-sdk android:minSdkVersion="18"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<application
|
<application
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities">
|
||||||
|
<!-- declaring that phone provides find_me capability -->
|
||||||
|
<item>find_me</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.findphone" >
|
package="com.example.android.wearable.findphone" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="20"
|
<uses-sdk android:minSdkVersion="20"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-feature android:name="android.hardware.type.watch" />
|
<uses-feature android:name="android.hardware.type.watch" />
|
||||||
|
|||||||
@@ -18,25 +18,105 @@ package com.example.android.wearable.findphone;
|
|||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
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.gms.wearable.WearableListenerService;
|
import com.google.android.gms.wearable.WearableListenerService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for disconnection from home device.
|
* Listens for changes in connectivity between this wear device and the phone. More precisely, we
|
||||||
|
* need to distinguish the case that the wear device and the phone are connected directly from all
|
||||||
|
* other possible cases. To this end, the phone app has registered itself to provide the "find_me"
|
||||||
|
* capability and we need to look for connected nodes that provide this capability AND are nearby,
|
||||||
|
* to exclude a connection through the cloud. The proper way would have been to use the
|
||||||
|
* {@code onCapabilitiesChanged()} callback but currently that callback cannot discover the case
|
||||||
|
* where a connection switches from wifi to direct; this shortcoming will be addressed in future
|
||||||
|
* updates but for now we will use the {@code onConnectedNodes()} callback.
|
||||||
*/
|
*/
|
||||||
public class DisconnectListenerService extends WearableListenerService {
|
public class DisconnectListenerService extends WearableListenerService
|
||||||
|
implements GoogleApiClient.ConnectionCallbacks {
|
||||||
|
|
||||||
private static final String TAG = "ExampleFindPhoneApp";
|
private static final String TAG = "ExampleFindPhoneApp";
|
||||||
|
|
||||||
private static final int FORGOT_PHONE_NOTIFICATION_ID = 1;
|
private static final int FORGOT_PHONE_NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
|
/* the capability that the phone app would provide */
|
||||||
|
private static final String FIND_ME_CAPABILITY_NAME = "find_me";
|
||||||
|
|
||||||
|
private GoogleApiClient mGoogleApiClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {
|
public void onCreate() {
|
||||||
// Create a "forgot phone" notification when phone connection is broken.
|
super.onCreate();
|
||||||
|
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||||
|
.addApi(Wearable.API)
|
||||||
|
.addConnectionCallbacks(this)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectedNodes(List<Node> connectedNodes) {
|
||||||
|
// After we are notified by this callback, we need to query for the nodes that provide the
|
||||||
|
// "find_me" capability and are directly connected.
|
||||||
|
if (mGoogleApiClient.isConnected()) {
|
||||||
|
setOrUpdateNotification();
|
||||||
|
} else if (!mGoogleApiClient.isConnecting()) {
|
||||||
|
mGoogleApiClient.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOrUpdateNotification() {
|
||||||
|
Wearable.CapabilityApi.getCapability(
|
||||||
|
mGoogleApiClient, FIND_ME_CAPABILITY_NAME,
|
||||||
|
CapabilityApi.FILTER_REACHABLE).setResultCallback(
|
||||||
|
new ResultCallback<CapabilityApi.GetCapabilityResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(CapabilityApi.GetCapabilityResult result) {
|
||||||
|
if (result.getStatus().isSuccess()) {
|
||||||
|
updateFindMeCapability(result.getCapability());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG,
|
||||||
|
"setOrUpdateNotification() Failed to get capabilities, "
|
||||||
|
+ "status: "
|
||||||
|
+ result.getStatus().getStatusMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFindMeCapability(CapabilityInfo capabilityInfo) {
|
||||||
|
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||||
|
if (connectedNodes.isEmpty()) {
|
||||||
|
setupLostConnectivityNotification();
|
||||||
|
} else {
|
||||||
|
for (Node node : connectedNodes) {
|
||||||
|
// we are only considering those nodes that are directly connected
|
||||||
|
if (node.isNearby()) {
|
||||||
|
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
|
||||||
|
.cancel(FORGOT_PHONE_NOTIFICATION_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a notification to inform user that the connectivity to phone has been lost (possibly
|
||||||
|
* left the phone behind).
|
||||||
|
*/
|
||||||
|
private void setupLostConnectivityNotification() {
|
||||||
Notification.Builder notificationBuilder = new Notification.Builder(this)
|
Notification.Builder notificationBuilder = new Notification.Builder(this)
|
||||||
.setContentTitle(getString(R.string.left_phone_title))
|
.setContentTitle(getString(R.string.left_phone_title))
|
||||||
.setContentText(getString(R.string.left_phone_content))
|
.setContentText(getString(R.string.left_phone_content))
|
||||||
.setVibrate(new long[] {0, 200}) // Vibrate for 200 milliseconds.
|
.setVibrate(new long[]{0, 200}) // Vibrate for 200 milliseconds.
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
.setLocalOnly(true)
|
.setLocalOnly(true)
|
||||||
.setPriority(Notification.PRIORITY_MAX);
|
.setPriority(Notification.PRIORITY_MAX);
|
||||||
@@ -46,10 +126,20 @@ public class DisconnectListenerService extends WearableListenerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {
|
public void onConnected(Bundle bundle) {
|
||||||
// Remove the "forgot phone" notification when connection is restored.
|
setOrUpdateNotification();
|
||||||
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
|
|
||||||
.cancel(FORGOT_PHONE_NOTIFICATION_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionSuspended(int cause) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting()) {
|
||||||
|
mGoogleApiClient.disconnect();
|
||||||
|
}
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import android.text.Spannable;
|
|||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.RelativeSizeSpan;
|
import android.text.style.RelativeSizeSpan;
|
||||||
|
|
||||||
|
|
||||||
public class FindPhoneActivity extends Activity {
|
public class FindPhoneActivity extends Activity {
|
||||||
|
|
||||||
private static final int FIND_PHONE_NOTIFICATION_ID = 2;
|
private static final int FIND_PHONE_NOTIFICATION_ID = 2;
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ public class FindPhoneService extends IntentService implements GoogleApiClient.C
|
|||||||
.getBoolean(FIELD_ALARM_ON, false);
|
.getBoolean(FIELD_ALARM_ON, false);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Unexpected number of DataItems found.\n"
|
Log.e(TAG, "Unexpected number of DataItems found.\n"
|
||||||
+ "\tExpected: 1\n"
|
+ "\tExpected: 1\n"
|
||||||
+ "\tActual: " + result.getCount());
|
+ "\tActual: " + result.getCount());
|
||||||
}
|
}
|
||||||
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
|
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||||
Log.d(TAG, "onHandleIntent: failed to get current alarm state");
|
Log.d(TAG, "onHandleIntent: failed to get current alarm state");
|
||||||
@@ -90,7 +90,7 @@ public class FindPhoneService extends IntentService implements GoogleApiClient.C
|
|||||||
alarmOn = !alarmOn;
|
alarmOn = !alarmOn;
|
||||||
// Change notification text based on new value of alarmOn.
|
// Change notification text based on new value of alarmOn.
|
||||||
String notificationText = alarmOn ? getString(R.string.turn_alarm_off)
|
String notificationText = alarmOn ? getString(R.string.turn_alarm_off)
|
||||||
: getString(R.string.turn_alarm_on);
|
: getString(R.string.turn_alarm_on);
|
||||||
FindPhoneActivity.updateNotification(this, notificationText);
|
FindPhoneActivity.updateNotification(this, notificationText);
|
||||||
}
|
}
|
||||||
// Use alarmOn boolean to update the DataItem - phone will respond accordingly
|
// Use alarmOn boolean to update the DataItem - phone will respond accordingly
|
||||||
@@ -101,7 +101,7 @@ public class FindPhoneService extends IntentService implements GoogleApiClient.C
|
|||||||
.await();
|
.await();
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Failed to toggle alarm on phone - Client disconnected from Google Play "
|
Log.e(TAG, "Failed to toggle alarm on phone - Client disconnected from Google Play "
|
||||||
+ "Services");
|
+ "Services");
|
||||||
}
|
}
|
||||||
mGoogleApiClient.disconnect();
|
mGoogleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package="com.example.android.wearable.quiz" >
|
package="com.example.android.wearable.quiz" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="18"
|
<uses-sdk android:minSdkVersion="18"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
7
samples/browseable/Quiz/Application/res/values/wear.xml
Normal file
7
samples/browseable/Quiz/Application/res/values/wear.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities">
|
||||||
|
<!-- declaring that phone provides reset_quiz capability -->
|
||||||
|
<item>reset_quiz</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
|
|
||||||
@@ -210,6 +210,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
* indexes. For example, question0 should come before question1.
|
* indexes. For example, question0 should come before question1.
|
||||||
*/
|
*/
|
||||||
private static class Question implements Comparable<Question> {
|
private static class Question implements Comparable<Question> {
|
||||||
|
|
||||||
private String question;
|
private String question;
|
||||||
private int questionIndex;
|
private int questionIndex;
|
||||||
private String[] answers;
|
private String[] answers;
|
||||||
@@ -253,6 +254,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a quiz, as defined in Quiz.json, when the user clicks on "Read quiz from file."
|
* Create a quiz, as defined in Quiz.json, when the user clicks on "Read quiz from file."
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void readQuizFromFile(View view) throws IOException, JSONException {
|
public void readQuizFromFile(View view) throws IOException, JSONException {
|
||||||
@@ -411,17 +413,18 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
private void sendMessageToWearable(final String path, final byte[] data) {
|
private void sendMessageToWearable(final String path, final byte[] data) {
|
||||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
||||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
|
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
|
||||||
for (Node node : nodes.getNodes()) {
|
for (Node node : nodes.getNodes()) {
|
||||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, data);
|
Wearable.MessageApi
|
||||||
}
|
.sendMessage(mGoogleApiClient, node.getId(), path, data);
|
||||||
|
}
|
||||||
|
|
||||||
if (path.equals(QUIZ_EXITED_PATH) && mGoogleApiClient.isConnected()) {
|
if (path.equals(QUIZ_EXITED_PATH) && mGoogleApiClient.isConnected()) {
|
||||||
mGoogleApiClient.disconnect();
|
mGoogleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -429,7 +432,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
*/
|
*/
|
||||||
public void resetQuiz(View view) {
|
public void resetQuiz(View view) {
|
||||||
// Reset quiz status in phone layout.
|
// Reset quiz status in phone layout.
|
||||||
for(int i = 0; i < questionsContainer.getChildCount(); i++) {
|
for (int i = 0; i < questionsContainer.getChildCount(); i++) {
|
||||||
LinearLayout questionStatusElement = (LinearLayout) questionsContainer.getChildAt(i);
|
LinearLayout questionStatusElement = (LinearLayout) questionsContainer.getChildAt(i);
|
||||||
TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
|
TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
|
||||||
TextView questionStatus = (TextView) questionStatusElement.findViewById(R.id.status);
|
TextView questionStatus = (TextView) questionStatusElement.findViewById(R.id.status);
|
||||||
@@ -481,11 +484,12 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
|||||||
* Callback that marks a DataItem, which represents a question, as unanswered and not deleted.
|
* Callback that marks a DataItem, which represents a question, as unanswered and not deleted.
|
||||||
*/
|
*/
|
||||||
private class ResetDataItemCallback implements ResultCallback<DataApi.DataItemResult> {
|
private class ResetDataItemCallback implements ResultCallback<DataApi.DataItemResult> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResult(DataApi.DataItemResult dataItemResult) {
|
public void onResult(DataApi.DataItemResult dataItemResult) {
|
||||||
if (dataItemResult.getStatus().isSuccess()) {
|
if (dataItemResult.getStatus().isSuccess()) {
|
||||||
PutDataMapRequest request = PutDataMapRequest.createFromDataMapItem(
|
PutDataMapRequest request = PutDataMapRequest.createFromDataMapItem(
|
||||||
DataMapItem.fromDataItem(dataItemResult.getDataItem()));
|
DataMapItem.fromDataItem(dataItemResult.getDataItem()));
|
||||||
DataMap dataMap = request.getDataMap();
|
DataMap dataMap = request.getDataMap();
|
||||||
dataMap.putBoolean(QUESTION_WAS_ANSWERED, false);
|
dataMap.putBoolean(QUESTION_WAS_ANSWERED, false);
|
||||||
dataMap.putBoolean(QUESTION_WAS_DELETED, false);
|
dataMap.putBoolean(QUESTION_WAS_DELETED, false);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="20"
|
<uses-sdk android:minSdkVersion="20"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.type.watch" />
|
<uses-feature android:name="android.hardware.type.watch" />
|
||||||
|
|
||||||
|
|||||||
@@ -38,4 +38,5 @@ public final class Constants {
|
|||||||
public static final String RESET_QUIZ_PATH = "/reset_quiz";
|
public static final String RESET_QUIZ_PATH = "/reset_quiz";
|
||||||
|
|
||||||
public static final int CONNECT_TIMEOUT_MS = 100;
|
public static final int CONNECT_TIMEOUT_MS = 100;
|
||||||
|
public static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.example.android.wearable.quiz;
|
package com.example.android.wearable.quiz;
|
||||||
|
|
||||||
|
import static com.example.android.wearable.quiz.Constants.CONNECT_TIMEOUT_MS;
|
||||||
|
import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_DELETED;
|
||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -33,9 +36,6 @@ import com.google.android.gms.wearable.Wearable;
|
|||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.example.android.wearable.quiz.Constants.CONNECT_TIMEOUT_MS;
|
|
||||||
import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_DELETED;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to update quiz status on the phone when user dismisses a question on the watch.
|
* Used to update quiz status on the phone when user dismisses a question on the watch.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* When the quiz ends, this listener receives a message telling it to create an end-of-quiz report.
|
* When the quiz ends, this listener receives a message telling it to create an end-of-quiz report.
|
||||||
*/
|
*/
|
||||||
public class QuizListenerService extends WearableListenerService {
|
public class QuizListenerService extends WearableListenerService {
|
||||||
|
|
||||||
private static final String TAG = "QuizSample";
|
private static final String TAG = "QuizSample";
|
||||||
private static final int QUIZ_REPORT_NOTIF_ID = -1; // Never used by question notifications.
|
private static final int QUIZ_REPORT_NOTIF_ID = -1; // Never used by question notifications.
|
||||||
private static final Map<Integer, Integer> questionNumToDrawableId;
|
private static final Map<Integer, Integer> questionNumToDrawableId;
|
||||||
|
|||||||
@@ -16,29 +16,34 @@
|
|||||||
|
|
||||||
package com.example.android.wearable.quiz;
|
package com.example.android.wearable.quiz;
|
||||||
|
|
||||||
|
import static com.example.android.wearable.quiz.Constants.CONNECT_TIMEOUT_MS;
|
||||||
|
import static com.example.android.wearable.quiz.Constants.GET_CAPABILITIES_TIMEOUT_MS;
|
||||||
|
import static com.example.android.wearable.quiz.Constants.RESET_QUIZ_PATH;
|
||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
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.Node;
|
||||||
import com.google.android.gms.wearable.NodeApi;
|
|
||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.example.android.wearable.quiz.Constants.CONNECT_TIMEOUT_MS;
|
|
||||||
import static com.example.android.wearable.quiz.Constants.RESET_QUIZ_PATH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to reset the quiz (by sending a message to the phone) when the Reset Quiz
|
* Service to reset the quiz (by sending a message to the phone) when the Reset Quiz
|
||||||
* action on the Quiz Report is selected.
|
* action on the Quiz Report is selected.
|
||||||
*/
|
*/
|
||||||
public class QuizReportActionService extends IntentService {
|
public class QuizReportActionService extends IntentService {
|
||||||
|
|
||||||
public static final String ACTION_RESET_QUIZ = "com.example.android.wearable.quiz.RESET_QUIZ";
|
public static final String ACTION_RESET_QUIZ = "com.example.android.wearable.quiz.RESET_QUIZ";
|
||||||
|
|
||||||
private static final String TAG = "QuizReportActionReceiver";
|
private static final String TAG = "QuizReportActionService";
|
||||||
|
private static final String RESET_QUIZ_CAPABILITY_NAME = "reset_quiz";
|
||||||
|
|
||||||
public QuizReportActionService() {
|
public QuizReportActionService() {
|
||||||
super(QuizReportActionService.class.getSimpleName());
|
super(QuizReportActionService.class.getSimpleName());
|
||||||
@@ -47,18 +52,35 @@ public class QuizReportActionService extends IntentService {
|
|||||||
@Override
|
@Override
|
||||||
public void onHandleIntent(Intent intent) {
|
public void onHandleIntent(Intent intent) {
|
||||||
if (intent.getAction().equals(ACTION_RESET_QUIZ)) {
|
if (intent.getAction().equals(ACTION_RESET_QUIZ)) {
|
||||||
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
|
final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addApi(Wearable.API)
|
.addApi(Wearable.API)
|
||||||
.build();
|
.build();
|
||||||
ConnectionResult result = googleApiClient.blockingConnect(CONNECT_TIMEOUT_MS,
|
ConnectionResult result = googleApiClient.blockingConnect(CONNECT_TIMEOUT_MS,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
if (!result.isSuccess()) {
|
if (!result.isSuccess()) {
|
||||||
Log.e(TAG, "QuizListenerService failed to connect to GoogleApiClient.");
|
Log.e(TAG, "QuizReportActionService failed to connect to GoogleApiClient.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi
|
||||||
for (Node node : nodes.getNodes()) {
|
.getCapability(googleApiClient, RESET_QUIZ_CAPABILITY_NAME,
|
||||||
|
CapabilityApi.FILTER_REACHABLE)
|
||||||
|
.await(GET_CAPABILITIES_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
if (capabilityResult.getStatus().isSuccess()) {
|
||||||
|
sendResetMessage(googleApiClient, capabilityResult.getCapability());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Failed to get capabilities, status: "
|
||||||
|
+ capabilityResult.getStatus().getStatusMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendResetMessage(GoogleApiClient googleApiClient, CapabilityInfo capabilityInfo) {
|
||||||
|
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||||
|
if (connectedNodes.isEmpty()) {
|
||||||
|
Log.w(TAG, "No node capable of resetting quiz was found");
|
||||||
|
} else {
|
||||||
|
for (Node node : connectedNodes) {
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), RESET_QUIZ_PATH,
|
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), RESET_QUIZ_PATH,
|
||||||
new byte[0]);
|
new byte[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.example.android.wearable.quiz;
|
package com.example.android.wearable.quiz;
|
||||||
|
|
||||||
|
import static com.example.android.wearable.quiz.Constants.CHOSEN_ANSWER_CORRECT;
|
||||||
|
import static com.example.android.wearable.quiz.Constants.QUESTION_INDEX;
|
||||||
|
import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_ANSWERED;
|
||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -34,15 +38,12 @@ import com.google.android.gms.wearable.Wearable;
|
|||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.example.android.wearable.quiz.Constants.CHOSEN_ANSWER_CORRECT;
|
|
||||||
import static com.example.android.wearable.quiz.Constants.QUESTION_INDEX;
|
|
||||||
import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_ANSWERED;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates quiz status on the phone when user selects an answer to a question on the watch.
|
* Updates quiz status on the phone when user selects an answer to a question on the watch.
|
||||||
*/
|
*/
|
||||||
public class UpdateQuestionService extends IntentService
|
public class UpdateQuestionService extends IntentService
|
||||||
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||||
|
|
||||||
public static final String EXTRA_QUESTION_CORRECT = "extra_question_correct";
|
public static final String EXTRA_QUESTION_CORRECT = "extra_question_correct";
|
||||||
public static final String EXTRA_QUESTION_INDEX = "extra_question_index";
|
public static final String EXTRA_QUESTION_INDEX = "extra_question_index";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities" translatable="false">
|
||||||
|
<!-- declaring that phone has the capability to show details -->
|
||||||
|
<item>@string/show_detail_capability_name</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="show_detail_capability_name">show_details</string>
|
||||||
|
</resources>
|
||||||
@@ -20,14 +20,19 @@ import android.app.IntentService;
|
|||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.example.android.xyztouristattractions.R;
|
||||||
import com.example.android.xyztouristattractions.common.Constants;
|
import com.example.android.xyztouristattractions.common.Constants;
|
||||||
import com.example.android.xyztouristattractions.common.Utils;
|
import com.example.android.xyztouristattractions.common.Utils;
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.wearable.CapabilityApi;
|
||||||
|
import com.google.android.gms.wearable.Node;
|
||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +40,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* operations that do not necessarily need to be tied to a UI.
|
* operations that do not necessarily need to be tied to a UI.
|
||||||
*/
|
*/
|
||||||
public class UtilityService extends IntentService {
|
public class UtilityService extends IntentService {
|
||||||
|
|
||||||
private static final String TAG = UtilityService.class.getSimpleName();
|
private static final String TAG = UtilityService.class.getSimpleName();
|
||||||
|
|
||||||
private static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
|
private static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
|
||||||
@@ -42,6 +48,7 @@ public class UtilityService extends IntentService {
|
|||||||
private static final String ACTION_START_DEVICE_ACTIVITY = "start_device_activity";
|
private static final String ACTION_START_DEVICE_ACTIVITY = "start_device_activity";
|
||||||
private static final String EXTRA_START_PATH = "start_path";
|
private static final String EXTRA_START_PATH = "start_path";
|
||||||
private static final String EXTRA_START_ACTIVITY_INFO = "start_activity_info";
|
private static final String EXTRA_START_ACTIVITY_INFO = "start_activity_info";
|
||||||
|
private static final long GET_CAPABILITY_TIMEOUT_S = 10;
|
||||||
|
|
||||||
public static void clearNotification(Context context) {
|
public static void clearNotification(Context context) {
|
||||||
Intent intent = new Intent(context, UtilityService.class);
|
Intent intent = new Intent(context, UtilityService.class);
|
||||||
@@ -131,7 +138,8 @@ public class UtilityService extends IntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the actual message to ask other devices to start an activity
|
* Sends the actual message to ask other devices that are capable of showing "details" to start
|
||||||
|
* the appropriate activity
|
||||||
*
|
*
|
||||||
* @param path the path to pass to the wearable message API
|
* @param path the path to pass to the wearable message API
|
||||||
* @param extraInfo extra info that varies based on the path being sent
|
* @param extraInfo extra info that varies based on the path being sent
|
||||||
@@ -145,14 +153,24 @@ public class UtilityService extends IntentService {
|
|||||||
Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS);
|
Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS);
|
||||||
|
|
||||||
if (connectionResult.isSuccess() && googleApiClient.isConnected()) {
|
if (connectionResult.isSuccess() && googleApiClient.isConnected()) {
|
||||||
Iterator<String> itr = Utils.getNodes(googleApiClient).iterator();
|
CapabilityApi.GetCapabilityResult result = Wearable.CapabilityApi.getCapability(
|
||||||
while (itr.hasNext()) {
|
googleApiClient,
|
||||||
// Loop through all connected nodes
|
getApplicationContext().getString(R.string.show_detail_capability_name),
|
||||||
Wearable.MessageApi.sendMessage(
|
CapabilityApi.FILTER_REACHABLE)
|
||||||
googleApiClient, itr.next(), path, extraInfo.getBytes());
|
.await(GET_CAPABILITY_TIMEOUT_S, TimeUnit.SECONDS);
|
||||||
|
if (result.getStatus().isSuccess()) {
|
||||||
|
Set<Node> nodes = result.getCapability().getNodes();
|
||||||
|
for (Node node : nodes) {
|
||||||
|
Wearable.MessageApi.sendMessage(
|
||||||
|
googleApiClient, node.getId(), path, extraInfo.getBytes());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "startDeviceActivityInternal() Failed to get capabilities, status: "
|
||||||
|
+ result.getStatus().getStatusMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
googleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
googleApiClient.disconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user