* commit '1d5ed62b1fac4db1aefa6a38a17afa5bfdc18837': Sync sample prebuilts to lmp-mr1-ub-docs
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
package="com.example.android.wearable.datalayer" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="18"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<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 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.ConnectionCallbacks;
|
||||
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.wearable.Asset;
|
||||
import com.google.android.gms.wearable.DataApi;
|
||||
import com.google.android.gms.wearable.DataApi.DataItemResult;
|
||||
import com.google.android.gms.wearable.DataEvent;
|
||||
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.SendMessageResult;
|
||||
import com.google.android.gms.wearable.MessageEvent;
|
||||
import com.google.android.gms.wearable.Node;
|
||||
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
|
||||
* item every second while it is open. Also allows user to take a photo and send that as an asset to
|
||||
* the paired wearable.
|
||||
* item every second while it is open. Also allows user to take a photo and send that as an asset
|
||||
* to the paired wearable.
|
||||
*/
|
||||
public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
MessageApi.MessageListener, NodeApi.NodeListener, ConnectionCallbacks,
|
||||
@@ -78,7 +78,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
|
||||
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 String START_ACTIVITY_PATH = "/start-activity";
|
||||
@@ -92,7 +94,6 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
private boolean mCameraSupported = false;
|
||||
|
||||
private ListView mDataItemList;
|
||||
private Button mTakePhotoBtn;
|
||||
private Button mSendPhotoBtn;
|
||||
private ImageView mThumbView;
|
||||
private Bitmap mImageBitmap;
|
||||
@@ -320,7 +321,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
}
|
||||
|
||||
private Collection<String> getNodes() {
|
||||
HashSet<String> results = new HashSet<String>();
|
||||
HashSet<String> results = new HashSet<>();
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
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) {
|
||||
LOGD(TAG, "Generating RPC");
|
||||
|
||||
@@ -367,7 +370,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
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 int count = 0;
|
||||
@@ -462,13 +467,9 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
* Sets up UI components and their callback handlers.
|
||||
*/
|
||||
private void setupViews() {
|
||||
mTakePhotoBtn = (Button) findViewById(R.id.takePhoto);
|
||||
mSendPhotoBtn = (Button) findViewById(R.id.sendPhoto);
|
||||
|
||||
// Shows the image received from the handset
|
||||
mThumbView = (ImageView) findViewById(R.id.imageView);
|
||||
mDataItemList = (ListView) findViewById(R.id.data_item_list);
|
||||
|
||||
mStartActivityBtn = findViewById(R.id.start_wearable_activity);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package="com.example.android.wearable.datalayer" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="20"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<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"
|
||||
android:id="@+id/layout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/dataItem_list"
|
||||
<android.support.wearable.view.GridViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:transcriptMode="alwaysScroll"/>
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/intro"
|
||||
<android.support.wearable.view.DotsPageIndicator
|
||||
android:id="@+id/page_indicator"
|
||||
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" />
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:padding="5dp"
|
||||
android:background="@drawable/rounded_background">
|
||||
</android.support.wearable.view.DotsPageIndicator>
|
||||
|
||||
</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">
|
||||
<string name="app_name">Data Layer Sample Wearable App</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>
|
||||
|
||||
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 IMAGE_PATH = "/image";
|
||||
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;
|
||||
|
||||
@Override
|
||||
@@ -63,11 +61,12 @@ public class DataLayerListenerService extends WearableListenerService {
|
||||
LOGD(TAG, "onDataChanged: " + dataEvents);
|
||||
final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);
|
||||
dataEvents.close();
|
||||
if(!mGoogleApiClient.isConnected()) {
|
||||
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting()) {
|
||||
ConnectionResult connectionResult = mGoogleApiClient
|
||||
.blockingConnect(30, TimeUnit.SECONDS);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,27 +19,33 @@ package com.example.android.wearable.datalayer;
|
||||
import static com.example.android.wearable.datalayer.DataLayerListenerService.LOGD;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Bundle;
|
||||
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.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
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.api.GoogleApiClient;
|
||||
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.ResultCallback;
|
||||
import com.google.android.gms.common.data.FreezableUtils;
|
||||
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.DataEvent;
|
||||
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 java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
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,
|
||||
OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener,
|
||||
NodeApi.NodeListener {
|
||||
|
||||
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 ListView mDataItemList;
|
||||
private TextView mIntroText;
|
||||
private DataItemAdapter mDataItemListAdapter;
|
||||
private View mLayout;
|
||||
private Handler mHandler;
|
||||
private GridViewPager mPager;
|
||||
private DataFragment mDataFragment;
|
||||
private AssetFragment mAssetFragment;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
mHandler = new Handler();
|
||||
LOGD(TAG, "onCreate");
|
||||
setContentView(R.layout.main_activity);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
mDataItemList = (ListView) findViewById(R.id.dataItem_list);
|
||||
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);
|
||||
|
||||
setupViews();
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.addConnectionCallbacks(this)
|
||||
@@ -128,8 +142,7 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mIntroText.setVisibility(View.INVISIBLE);
|
||||
mDataItemListAdapter.add(new Event(title, text));
|
||||
mDataFragment.appendItem(title, text);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,8 +164,9 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Setting background image..");
|
||||
mLayout.setBackground(new BitmapDrawable(getResources(), bitmap));
|
||||
Log.d(TAG, "Setting background image on second page..");
|
||||
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
|
||||
* {@link com.google.android.gms.wearable.Asset}
|
||||
@@ -206,50 +284,53 @@ public class MainActivity extends Activity implements ConnectionCallbacks,
|
||||
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) {
|
||||
super(context, unusedResource);
|
||||
mContext = context;
|
||||
private class MyPagerAdapter extends FragmentGridPagerAdapter {
|
||||
|
||||
private List<Fragment> mFragments;
|
||||
|
||||
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
|
||||
super(fm);
|
||||
mFragments = fragments;
|
||||
}
|
||||
|
||||
@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;
|
||||
public int getRowCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
|
||||
TextView text1;
|
||||
TextView text2;
|
||||
@Override
|
||||
public int getColumnCount(int row) {
|
||||
return mFragments == null ? 0 : mFragments.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class Event {
|
||||
|
||||
String title;
|
||||
String text;
|
||||
|
||||
public Event(String title, String text) {
|
||||
this.title = title;
|
||||
this.text = text;
|
||||
@Override
|
||||
public Fragment getFragment(int row, int column) {
|
||||
return mFragments.get(column);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="18"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<application
|
||||
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) {
|
||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||
@Override
|
||||
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
||||
for (final Node node : getConnectedNodesResult.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(
|
||||
mGoogleApiClient, node.getId(), START_ACTIVITY_PATH, new byte[0])
|
||||
.setResultCallback(getSendMessageResultCallback());
|
||||
}
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
||||
for (final Node node : getConnectedNodesResult.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(),
|
||||
START_ACTIVITY_PATH, new byte[0]).setResultCallback(
|
||||
getSendMessageResultCallback());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback() {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package="com.example.android.wearable.delayedconfirmation" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="20"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<uses-feature android:name="android.hardware.type.watch" />
|
||||
|
||||
|
||||
@@ -22,4 +22,5 @@
|
||||
<string name="notification_title">DelayedConfirmation</string>
|
||||
<string name="notification_timer_selected">Timer Selected</string>
|
||||
<string name="notification_timer_finished">Timer Finished</string>
|
||||
<string name="no_device_found">No device able to confirm was found</string>
|
||||
</resources>
|
||||
|
||||
@@ -23,19 +23,23 @@ import android.os.Bundle;
|
||||
import android.support.wearable.view.DelayedConfirmationView;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
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.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.Node;
|
||||
import com.google.android.gms.wearable.NodeApi;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class MainActivity extends Activity implements
|
||||
DelayedConfirmationView.DelayedConfirmationListener,
|
||||
GoogleApiClient.OnConnectionFailedListener {
|
||||
GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
|
||||
CapabilityApi.CapabilityListener {
|
||||
|
||||
private static final String TAG = "DelayedConfirmation";
|
||||
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_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 GoogleApiClient mGoogleApiClient;
|
||||
|
||||
/* the preferred note that can handle the confirmation capability */
|
||||
private Node mConfirmationHandlerNode;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
@@ -55,6 +65,7 @@ public class MainActivity extends Activity implements
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.addConnectionCallbacks(this)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -67,11 +78,13 @@ public class MainActivity extends Activity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
protected void onPause() {
|
||||
if (mGoogleApiClient.isConnected()) {
|
||||
Wearable.CapabilityApi.removeCapabilityListener(mGoogleApiClient, this,
|
||||
CONFIRMATION_HANDLER_CAPABILITY_NAME);
|
||||
mGoogleApiClient.disconnect();
|
||||
}
|
||||
super.onDestroy();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,32 +125,94 @@ public class MainActivity extends Activity implements
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.e(TAG, "Failed to connect to Google Api Client");
|
||||
mConfirmationHandlerNode = null;
|
||||
}
|
||||
|
||||
private void sendMessageToCompanion(final String path) {
|
||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||
@Override
|
||||
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
|
||||
for (final Node node : getConnectedNodesResult.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path,
|
||||
new byte[0]).setResultCallback(getSendMessageResultCallback());
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (mConfirmationHandlerNode != null) {
|
||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, mConfirmationHandlerNode.getId(),
|
||||
path, new byte[0])
|
||||
.setResultCallback(getSendMessageResultCallback(mConfirmationHandlerNode));
|
||||
} else {
|
||||
Toast.makeText(this, R.string.no_device_found, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback() {
|
||||
private ResultCallback<MessageApi.SendMessageResult> getSendMessageResultCallback(
|
||||
final Node node) {
|
||||
return new ResultCallback<MessageApi.SendMessageResult>() {
|
||||
@Override
|
||||
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
|
||||
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());
|
||||
} 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.
|
||||
*/
|
||||
public class WearableMessageListenerService extends WearableListenerService {
|
||||
|
||||
private static final String START_ACTIVITY_PATH = "/start-activity";
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package="com.example.android.wearable.findphone">
|
||||
|
||||
<uses-sdk android:minSdkVersion="18"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<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" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="20"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<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.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 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 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
|
||||
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {
|
||||
// Create a "forgot phone" notification when phone connection is broken.
|
||||
public void onCreate() {
|
||||
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)
|
||||
.setContentTitle(getString(R.string.left_phone_title))
|
||||
.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)
|
||||
.setLocalOnly(true)
|
||||
.setPriority(Notification.PRIORITY_MAX);
|
||||
@@ -46,10 +126,20 @@ public class DisconnectListenerService extends WearableListenerService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {
|
||||
// Remove the "forgot phone" notification when connection is restored.
|
||||
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
|
||||
.cancel(FORGOT_PHONE_NOTIFICATION_ID);
|
||||
public void onConnected(Bundle bundle) {
|
||||
setOrUpdateNotification();
|
||||
}
|
||||
|
||||
@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.style.RelativeSizeSpan;
|
||||
|
||||
|
||||
public class FindPhoneActivity extends Activity {
|
||||
|
||||
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);
|
||||
} else {
|
||||
Log.e(TAG, "Unexpected number of DataItems found.\n"
|
||||
+ "\tExpected: 1\n"
|
||||
+ "\tActual: " + result.getCount());
|
||||
+ "\tExpected: 1\n"
|
||||
+ "\tActual: " + result.getCount());
|
||||
}
|
||||
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "onHandleIntent: failed to get current alarm state");
|
||||
@@ -90,7 +90,7 @@ public class FindPhoneService extends IntentService implements GoogleApiClient.C
|
||||
alarmOn = !alarmOn;
|
||||
// Change notification text based on new value of alarmOn.
|
||||
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);
|
||||
}
|
||||
// Use alarmOn boolean to update the DataItem - phone will respond accordingly
|
||||
@@ -101,7 +101,7 @@ public class FindPhoneService extends IntentService implements GoogleApiClient.C
|
||||
.await();
|
||||
} else {
|
||||
Log.e(TAG, "Failed to toggle alarm on phone - Client disconnected from Google Play "
|
||||
+ "Services");
|
||||
+ "Services");
|
||||
}
|
||||
mGoogleApiClient.disconnect();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package="com.example.android.wearable.quiz" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="18"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<application
|
||||
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.
|
||||
*/
|
||||
private static class Question implements Comparable<Question> {
|
||||
|
||||
private String question;
|
||||
private int questionIndex;
|
||||
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."
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
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) {
|
||||
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
|
||||
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||
@Override
|
||||
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, data);
|
||||
}
|
||||
@Override
|
||||
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi
|
||||
.sendMessage(mGoogleApiClient, node.getId(), path, data);
|
||||
}
|
||||
|
||||
if (path.equals(QUIZ_EXITED_PATH) && mGoogleApiClient.isConnected()) {
|
||||
mGoogleApiClient.disconnect();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (path.equals(QUIZ_EXITED_PATH) && mGoogleApiClient.isConnected()) {
|
||||
mGoogleApiClient.disconnect();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,7 +432,7 @@ public class MainActivity extends Activity implements DataApi.DataListener,
|
||||
*/
|
||||
public void resetQuiz(View view) {
|
||||
// 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);
|
||||
TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
|
||||
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.
|
||||
*/
|
||||
private class ResetDataItemCallback implements ResultCallback<DataApi.DataItemResult> {
|
||||
|
||||
@Override
|
||||
public void onResult(DataApi.DataItemResult dataItemResult) {
|
||||
if (dataItemResult.getStatus().isSuccess()) {
|
||||
PutDataMapRequest request = PutDataMapRequest.createFromDataMapItem(
|
||||
DataMapItem.fromDataItem(dataItemResult.getDataItem()));
|
||||
DataMapItem.fromDataItem(dataItemResult.getDataItem()));
|
||||
DataMap dataMap = request.getDataMap();
|
||||
dataMap.putBoolean(QUESTION_WAS_ANSWERED, false);
|
||||
dataMap.putBoolean(QUESTION_WAS_DELETED, false);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
<uses-sdk android:minSdkVersion="20"
|
||||
android:targetSdkVersion="21" />
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<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 int CONNECT_TIMEOUT_MS = 100;
|
||||
public static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
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.content.Intent;
|
||||
import android.net.Uri;
|
||||
@@ -33,9 +36,6 @@ import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
public class QuizListenerService extends WearableListenerService {
|
||||
|
||||
private static final String TAG = "QuizSample";
|
||||
private static final int QUIZ_REPORT_NOTIF_ID = -1; // Never used by question notifications.
|
||||
private static final Map<Integer, Integer> questionNumToDrawableId;
|
||||
|
||||
@@ -16,29 +16,34 @@
|
||||
|
||||
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.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
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.NodeApi;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
import java.util.Set;
|
||||
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
|
||||
* action on the Quiz Report is selected.
|
||||
*/
|
||||
public class QuizReportActionService extends IntentService {
|
||||
|
||||
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() {
|
||||
super(QuizReportActionService.class.getSimpleName());
|
||||
@@ -47,18 +52,35 @@ public class QuizReportActionService extends IntentService {
|
||||
@Override
|
||||
public void onHandleIntent(Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_RESET_QUIZ)) {
|
||||
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
|
||||
final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
ConnectionResult result = googleApiClient.blockingConnect(CONNECT_TIMEOUT_MS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
if (!result.isSuccess()) {
|
||||
Log.e(TAG, "QuizListenerService failed to connect to GoogleApiClient.");
|
||||
Log.e(TAG, "QuizReportActionService failed to connect to GoogleApiClient.");
|
||||
return;
|
||||
}
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
|
||||
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi
|
||||
.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,
|
||||
new byte[0]);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
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.NotificationManager;
|
||||
import android.content.Intent;
|
||||
@@ -34,15 +38,12 @@ import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
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.
|
||||
*/
|
||||
public class UpdateQuestionService extends IntentService
|
||||
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
|
||||
public static final String EXTRA_QUESTION_CORRECT = "extra_question_correct";
|
||||
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.content.Context;
|
||||
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.Utils;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
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 java.util.Iterator;
|
||||
import java.util.Set;
|
||||
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.
|
||||
*/
|
||||
public class UtilityService extends IntentService {
|
||||
|
||||
private static final String TAG = UtilityService.class.getSimpleName();
|
||||
|
||||
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 EXTRA_START_PATH = "start_path";
|
||||
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) {
|
||||
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 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);
|
||||
|
||||
if (connectionResult.isSuccess() && googleApiClient.isConnected()) {
|
||||
Iterator<String> itr = Utils.getNodes(googleApiClient).iterator();
|
||||
while (itr.hasNext()) {
|
||||
// Loop through all connected nodes
|
||||
Wearable.MessageApi.sendMessage(
|
||||
googleApiClient, itr.next(), path, extraInfo.getBytes());
|
||||
CapabilityApi.GetCapabilityResult result = Wearable.CapabilityApi.getCapability(
|
||||
googleApiClient,
|
||||
getApplicationContext().getString(R.string.show_detail_capability_name),
|
||||
CapabilityApi.FILTER_REACHABLE)
|
||||
.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