Merge "Adding appropriate logic to check if speaker is supported on the wear device and if not, show a message to user." into mnc-docs
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
index 5086a17..26832f2 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
@@ -16,12 +16,10 @@
package com.example.android.asymmetricfingerprintdialog;
-import android.Manifest;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
@@ -59,8 +57,6 @@
/** Alias for our key in the Android Key Store */
public static final String KEY_NAME = "my_key";
- private static final int FINGERPRINT_PERMISSION_REQUEST_CODE = 0;
-
@Inject KeyguardManager mKeyguardManager;
@Inject FingerprintManager mFingerprintManager;
@Inject FingerprintAuthenticationDialogFragment mFragment;
@@ -74,71 +70,63 @@
super.onCreate(savedInstanceState);
((InjectedApplication) getApplication()).inject(this);
- requestPermissions(new String[]{Manifest.permission.USE_FINGERPRINT},
- FINGERPRINT_PERMISSION_REQUEST_CODE);
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] state) {
- if (requestCode == FINGERPRINT_PERMISSION_REQUEST_CODE
- && state[0] == PackageManager.PERMISSION_GRANTED) {
- setContentView(R.layout.activity_main);
- Button purchaseButton = (Button) findViewById(R.id.purchase_button);
- if (!mKeyguardManager.isKeyguardSecure()) {
- // Show a message that the user hasn't set up a fingerprint or lock screen.
- Toast.makeText(this,
- "Secure lock screen hasn't set up.\n"
- + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint",
- Toast.LENGTH_LONG).show();
- purchaseButton.setEnabled(false);
- return;
- }
- if (!mFingerprintManager.hasEnrolledFingerprints()) {
- purchaseButton.setEnabled(false);
- // This happens when no fingerprints are registered.
- Toast.makeText(this,
- "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
- Toast.LENGTH_LONG).show();
- return;
- }
- createKeyPair();
- purchaseButton.setEnabled(true);
- purchaseButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- findViewById(R.id.confirmation_message).setVisibility(View.GONE);
- findViewById(R.id.encrypted_message).setVisibility(View.GONE);
-
- // Set up the crypto object for later. The object will be authenticated by use
- // of the fingerprint.
- if (initSignature()) {
-
- // Show the fingerprint dialog. The user has the option to use the fingerprint with
- // crypto, or you can fall back to using a server-side verified password.
- mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mSignature));
- boolean useFingerprintPreference = mSharedPreferences
- .getBoolean(getString(R.string.use_fingerprint_to_authenticate_key),
- true);
- if (useFingerprintPreference) {
- mFragment.setStage(
- FingerprintAuthenticationDialogFragment.Stage.FINGERPRINT);
- } else {
- mFragment.setStage(
- FingerprintAuthenticationDialogFragment.Stage.PASSWORD);
- }
- mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
- } else {
- // This happens if the lock screen has been disabled or or a fingerprint got
- // enrolled. Thus show the dialog to authenticate with their password first
- // and ask the user if they want to authenticate with fingerprints in the
- // future
- mFragment.setStage(
- FingerprintAuthenticationDialogFragment.Stage.NEW_FINGERPRINT_ENROLLED);
- mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
- }
- }
- });
+ setContentView(R.layout.activity_main);
+ Button purchaseButton = (Button) findViewById(R.id.purchase_button);
+ if (!mKeyguardManager.isKeyguardSecure()) {
+ // Show a message that the user hasn't set up a fingerprint or lock screen.
+ Toast.makeText(this,
+ "Secure lock screen hasn't set up.\n"
+ + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint",
+ Toast.LENGTH_LONG).show();
+ purchaseButton.setEnabled(false);
+ return;
}
+ //noinspection ResourceType
+ if (!mFingerprintManager.hasEnrolledFingerprints()) {
+ purchaseButton.setEnabled(false);
+ // This happens when no fingerprints are registered.
+ Toast.makeText(this,
+ "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+ createKeyPair();
+ purchaseButton.setEnabled(true);
+ purchaseButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ findViewById(R.id.confirmation_message).setVisibility(View.GONE);
+ findViewById(R.id.encrypted_message).setVisibility(View.GONE);
+
+ // Set up the crypto object for later. The object will be authenticated by use
+ // of the fingerprint.
+ if (initSignature()) {
+
+ // Show the fingerprint dialog. The user has the option to use the fingerprint with
+ // crypto, or you can fall back to using a server-side verified password.
+ mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mSignature));
+ boolean useFingerprintPreference = mSharedPreferences
+ .getBoolean(getString(R.string.use_fingerprint_to_authenticate_key),
+ true);
+ if (useFingerprintPreference) {
+ mFragment.setStage(
+ FingerprintAuthenticationDialogFragment.Stage.FINGERPRINT);
+ } else {
+ mFragment.setStage(
+ FingerprintAuthenticationDialogFragment.Stage.PASSWORD);
+ }
+ mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
+ } else {
+ // This happens if the lock screen has been disabled or or a fingerprint got
+ // enrolled. Thus show the dialog to authenticate with their password first
+ // and ask the user if they want to authenticate with fingerprints in the
+ // future
+ mFragment.setStage(
+ FingerprintAuthenticationDialogFragment.Stage.NEW_FINGERPRINT_ENROLLED);
+ mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
+ }
+ }
+ });
}
/**
diff --git a/security/keystore/BasicAndroidKeyStore/Application/src/main/java/com/example/android/basicandroidkeystore/BasicAndroidKeyStoreFragment.java b/security/keystore/BasicAndroidKeyStore/Application/src/main/java/com/example/android/basicandroidkeystore/BasicAndroidKeyStoreFragment.java
index 12873e8..e6244bf 100644
--- a/security/keystore/BasicAndroidKeyStore/Application/src/main/java/com/example/android/basicandroidkeystore/BasicAndroidKeyStoreFragment.java
+++ b/security/keystore/BasicAndroidKeyStore/Application/src/main/java/com/example/android/basicandroidkeystore/BasicAndroidKeyStoreFragment.java
@@ -156,7 +156,7 @@
// generated.
Calendar start = new GregorianCalendar();
Calendar end = new GregorianCalendar();
- end.add(1, Calendar.YEAR);
+ end.add(Calendar.YEAR, 1);
//END_INCLUDE(create_valid_dates)
@@ -316,8 +316,7 @@
// Verify the data.
s.initVerify(((KeyStore.PrivateKeyEntry) entry).getCertificate());
s.update(data);
- boolean valid = s.verify(signature);
- return valid;
+ return s.verify(signature);
// END_INCLUDE(verify_data)
}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
index 9a3f04b..026107e 100644
--- a/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 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.
@@ -13,12 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.wearable.watchface" >
+ package="com.example.android.wearable.watchface" >
- <uses-sdk android:minSdkVersion="21"
- android:targetSdkVersion="22" />
+ <uses-sdk
+ android:minSdkVersion="21"
+ android:targetSdkVersion="23" />
<uses-feature android:name="android.hardware.type.watch" />
@@ -33,101 +34,109 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+
+ <meta-data
+ android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version" />
+
+ <uses-library android:name="com.google.android.wearable" android:required="false" />
<service
- android:name=".AnalogWatchFaceService"
- android:label="@string/analog_name"
- android:permission="android.permission.BIND_WALLPAPER" >
+ android:name=".AnalogWatchFaceService"
+ android:label="@string/analog_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
<meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_analog" />
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_analog" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_analog_circular" />
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_analog_circular" />
<meta-data
- android:name="com.google.android.wearable.watchface.companionConfigurationAction"
- android:value="com.example.android.wearable.watchface.CONFIG_ANALOG" />
- <intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
- <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
- </intent-filter>
- </service>
-
- <service
- android:name=".SweepWatchFaceService"
- android:label="@string/sweep_name"
- android:permission="android.permission.BIND_WALLPAPER" >
- <meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
- <meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_analog" />
- <meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_analog_circular" />
- <intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
- <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
- </intent-filter>
- </service>
-
- <service
- android:name=".OpenGLWatchFaceService"
- android:label="@string/opengl_name"
- android:permission="android.permission.BIND_WALLPAPER" >
- <meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
- <meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_opengl" />
- <meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_opengl_circular" />
- <meta-data
- android:name="com.google.android.wearable.watchface.companionConfigurationAction"
- android:value="com.example.android.wearable.watchface.CONFIG_OPENGL" />
+ android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+ android:value="com.example.android.wearable.watchface.CONFIG_ANALOG" />
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
-
<service
- android:name=".CardBoundsWatchFaceService"
- android:label="@string/card_bounds_name"
- android:permission="android.permission.BIND_WALLPAPER" >
+ android:name=".SweepWatchFaceService"
+ android:label="@string/sweep_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
<meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_card_bounds" />
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_analog" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_card_bounds_circular" />
- <meta-data
- android:name="com.google.android.wearable.watchface.companionConfigurationAction"
- android:value="com.example.android.wearable.watchface.CONFIG_CARD_BOUNDS" />
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_analog_circular" />
+
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
-
-
<service
- android:name=".InteractiveWatchFaceService"
- android:label="@string/interactive_name"
- android:permission="android.permission.BIND_WALLPAPER" >
+ android:name=".OpenGLWatchFaceService"
+ android:label="@string/opengl_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
+ <meta-data
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_opengl" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_opengl_circular" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+ android:value="com.example.android.wearable.watchface.CONFIG_OPENGL" />
+
+ <intent-filter>
+ <action android:name="android.service.wallpaper.WallpaperService" />
+
+ <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+ </intent-filter>
+ </service>
+ <service
+ android:name=".CardBoundsWatchFaceService"
+ android:label="@string/card_bounds_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
+ <meta-data
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_card_bounds" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_card_bounds_circular" />
+ <meta-data
+ android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+ android:value="com.example.android.wearable.watchface.CONFIG_CARD_BOUNDS" />
+
+ <intent-filter>
+ <action android:name="android.service.wallpaper.WallpaperService" />
+
+ <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+ </intent-filter>
+ </service>
+ <service
+ android:name=".InteractiveWatchFaceService"
+ android:label="@string/interactive_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/watch_face" />
@@ -137,77 +146,82 @@
<meta-data
android:name="com.google.android.wearable.watchface.preview_circular"
android:resource="@drawable/preview_interactive_circular" />
+
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
- <category
- android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+
+ <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
-
<service
- android:name=".DigitalWatchFaceService"
- android:label="@string/digital_name"
- android:permission="android.permission.BIND_WALLPAPER" >
+ android:name=".DigitalWatchFaceService"
+ android:label="@string/digital_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
<meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_digital" />
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_digital" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_digital_circular" />
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_digital_circular" />
<meta-data
- android:name="com.google.android.wearable.watchface.companionConfigurationAction"
- android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+ android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+ android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
<meta-data
- android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
- android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+ android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
+ android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
- <!-- All intent-filters for config actions must include the categories
+ <!--
+ All intent-filters for config actions must include the categories
com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION
- and android.intent.category.DEFAULT. -->
+ and android.intent.category.DEFAULT.
+ -->
<activity
- android:name=".DigitalWatchFaceWearableConfigActivity"
- android:label="@string/digital_config_name">
+ android:name=".DigitalWatchFaceWearableConfigActivity"
+ android:label="@string/digital_config_name" >
<intent-filter>
<action android:name="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+
<category android:name="com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
- android:name=".CalendarWatchFaceService"
- android:label="@string/calendar_name"
- android:permission="android.permission.BIND_WALLPAPER" >
+ android:name=".CalendarWatchFaceService"
+ android:label="@string/calendar_name"
+ android:permission="android.permission.BIND_WALLPAPER" >
<meta-data
- android:name="android.service.wallpaper"
- android:resource="@xml/watch_face" />
+ android:name="android.service.wallpaper"
+ android:resource="@xml/watch_face" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview"
- android:resource="@drawable/preview_calendar" />
+ android:name="com.google.android.wearable.watchface.preview"
+ android:resource="@drawable/preview_calendar" />
<meta-data
- android:name="com.google.android.wearable.watchface.preview_circular"
- android:resource="@drawable/preview_calendar_circular" />
+ android:name="com.google.android.wearable.watchface.preview_circular"
+ android:resource="@drawable/preview_calendar_circular" />
+
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
-
- <service android:name=".DigitalWatchFaceConfigListenerService">
+ <service android:name=".DigitalWatchFaceConfigListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
-
<service
android:name=".FitDistanceWatchFaceService"
android:label="@string/fit_distance_name"
@@ -221,17 +235,16 @@
<meta-data
android:name="com.google.android.wearable.watchface.preview_circular"
android:resource="@drawable/preview_distance_circular" />
-
<meta-data
android:name="com.google.android.wearable.watchface.companionConfigurationAction"
android:value="com.example.android.wearable.watchface.CONFIG_FIT_DISTANCE" />
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
-
<service
android:name=".FitStepsWatchFaceService"
android:label="@string/fit_steps_name"
@@ -248,14 +261,15 @@
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
+
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
- <meta-data
- android:name="com.google.android.gms.version"
- android:value="@integer/google_play_services_version" />
-
+ <activity
+ android:name=".CalendarWatchFacePermissionActivity"
+ android:label="@string/title_activity_calendar_watch_face_permission" >
+ </activity>
</application>
</manifest>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFacePermissionActivity.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFacePermissionActivity.java
new file mode 100644
index 0000000..7effd33
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFacePermissionActivity.java
@@ -0,0 +1,56 @@
+package com.example.android.wearable.watchface;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.wearable.activity.WearableActivity;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * Simple Activity for displaying Calendar Permission Rationale to user.
+ */
+public class CalendarWatchFacePermissionActivity extends WearableActivity {
+
+ private static final String TAG = "PermissionActivity";
+
+ /* Id to identify permission request for calendar. */
+ private static final int PERMISSION_REQUEST_READ_CALENDAR = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_calendar_watch_face_permission);
+ setAmbientEnabled();
+ }
+
+ public void onClickEnablePermission(View view) {
+ Log.d(TAG, "onClickEnablePermission()");
+
+ // On 23+ (M+) devices, GPS permission not granted. Request permission.
+ ActivityCompat.requestPermissions(
+ this,
+ new String[]{Manifest.permission.READ_CALENDAR},
+ PERMISSION_REQUEST_READ_CALENDAR);
+
+ }
+
+ /*
+ * Callback received when a permissions request has been completed.
+ */
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+
+ Log.d(TAG, "onRequestPermissionsResult()");
+
+ if (requestCode == PERMISSION_REQUEST_READ_CALENDAR) {
+ if ((grantResults.length == 1)
+ && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ finish();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java
index a8ab955..98a251c 100644
--- a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java
@@ -16,11 +16,13 @@
package com.example.android.wearable.watchface;
+import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -30,8 +32,10 @@
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
+import android.support.v4.app.ActivityCompat;
import android.support.wearable.provider.WearableCalendarContract;
import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceService;
import android.support.wearable.watchface.WatchFaceStyle;
import android.text.DynamicLayout;
import android.text.Editable;
@@ -74,31 +78,37 @@
final TextPaint mTextPaint = new TextPaint();
int mNumMeetings;
+ private boolean mCalendarPermissionApproved;
+ private String mCalendarNotApprovedMessage;
private AsyncTask<Void, Void, Integer> mLoadMeetingsTask;
+ private boolean mIsReceiverRegistered;
+
/** Handler to load the meetings once a minute in interactive mode. */
final Handler mLoadMeetingsHandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_LOAD_MEETINGS:
+
cancelLoadMeetingTask();
- mLoadMeetingsTask = new LoadMeetingsTask();
- mLoadMeetingsTask.execute();
+
+ // Loads meetings.
+ if (mCalendarPermissionApproved) {
+ mLoadMeetingsTask = new LoadMeetingsTask();
+ mLoadMeetingsTask.execute();
+ }
break;
}
}
};
- private boolean mIsReceiverRegistered;
-
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_PROVIDER_CHANGED.equals(intent.getAction())
&& WearableCalendarContract.CONTENT_URI.equals(intent.getData())) {
- cancelLoadMeetingTask();
mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
}
}
@@ -106,29 +116,59 @@
@Override
public void onCreate(SurfaceHolder holder) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onCreate");
- }
super.onCreate(holder);
+ Log.d(TAG, "onCreate");
+
+ mCalendarNotApprovedMessage =
+ getResources().getString(R.string.calendar_permission_not_approved);
+
+ /* Accepts tap events to allow permission changes by user. */
setWatchFaceStyle(new WatchFaceStyle.Builder(CalendarWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
+ .setAcceptsTapEvents(true)
.build());
mTextPaint.setColor(FOREGROUND_COLOR);
mTextPaint.setTextSize(TEXT_SIZE);
- mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
+ // Enables app to handle 23+ (M+) style permissions.
+ mCalendarPermissionApproved =
+ ActivityCompat.checkSelfPermission(
+ getApplicationContext(),
+ Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED;
+
+ if (mCalendarPermissionApproved) {
+ mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
+ }
}
@Override
public void onDestroy() {
mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS);
- cancelLoadMeetingTask();
super.onDestroy();
}
+ /*
+ * Captures tap event (and tap type) and increments correct tap type total.
+ */
+ @Override
+ public void onTapCommand(int tapType, int x, int y, long eventTime) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Tap Command: " + tapType);
+ }
+
+ // Ignore lint error (fixed in wearable support library 1.4)
+ if (tapType == WatchFaceService.TAP_TYPE_TAP && !mCalendarPermissionApproved) {
+ Intent permissionIntent = new Intent(
+ getApplicationContext(),
+ CalendarWatchFacePermissionActivity.class);
+ permissionIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(permissionIntent);
+ }
+ }
+
@Override
public void onDraw(Canvas canvas, Rect bounds) {
// Create or update mLayout if necessary.
@@ -141,8 +181,13 @@
// Update the contents of mEditable.
mEditable.clear();
- mEditable.append(Html.fromHtml(getResources().getQuantityString(
- R.plurals.calendar_meetings, mNumMeetings, mNumMeetings)));
+
+ if (mCalendarPermissionApproved) {
+ mEditable.append(Html.fromHtml(getResources().getQuantityString(
+ R.plurals.calendar_meetings, mNumMeetings, mNumMeetings)));
+ } else {
+ mEditable.append(Html.fromHtml(mCalendarNotApprovedMessage));
+ }
// Draw the text on a solid background.
canvas.drawColor(BACKGROUND_COLOR);
@@ -151,15 +196,24 @@
@Override
public void onVisibilityChanged(boolean visible) {
+ Log.d(TAG, "onVisibilityChanged()");
super.onVisibilityChanged(visible);
if (visible) {
- IntentFilter filter = new IntentFilter(Intent.ACTION_PROVIDER_CHANGED);
- filter.addDataScheme("content");
- filter.addDataAuthority(WearableCalendarContract.AUTHORITY, null);
- registerReceiver(mBroadcastReceiver, filter);
- mIsReceiverRegistered = true;
- mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
+ // Enables app to handle 23+ (M+) style permissions.
+ mCalendarPermissionApproved = ActivityCompat.checkSelfPermission(
+ getApplicationContext(),
+ Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED;
+
+ if (mCalendarPermissionApproved) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PROVIDER_CHANGED);
+ filter.addDataScheme("content");
+ filter.addDataAuthority(WearableCalendarContract.AUTHORITY, null);
+ registerReceiver(mBroadcastReceiver, filter);
+ mIsReceiverRegistered = true;
+
+ mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
+ }
} else {
if (mIsReceiverRegistered) {
unregisterReceiver(mBroadcastReceiver);
@@ -204,9 +258,9 @@
final Cursor cursor = getContentResolver().query(builder.build(),
null, null, null, null);
int numMeetings = cursor.getCount();
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Num meetings: " + numMeetings);
- }
+
+ Log.d(TAG, "Num meetings: " + numMeetings);
+
return numMeetings;
}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_lock_open_white_24dp.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_lock_open_white_24dp.png
new file mode 100644
index 0000000..6bae68f
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_lock_open_white_24dp.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_lock_open_white_24dp.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_lock_open_white_24dp.png
new file mode 100644
index 0000000..3f47b54
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_lock_open_white_24dp.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_lock_open_white_24dp.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_lock_open_white_24dp.png
new file mode 100644
index 0000000..cbe9e1c
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_lock_open_white_24dp.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_lock_open_white_24dp.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_lock_open_white_24dp.png
new file mode 100644
index 0000000..1d1b0f4
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_lock_open_white_24dp.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_calendar_watch_face_permission.xml b/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_calendar_watch_face_permission.xml
new file mode 100644
index 0000000..bf0e3f6
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_calendar_watch_face_permission.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.wearable.view.BoxInsetLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/container"
+ android:background="@color/white"
+ android:paddingTop="32dp"
+ android:paddingLeft="36dp"
+ android:paddingRight="22dp"
+ tools:context="com.example.android.wearable.watchface.CalendarWatchFacePermissionActivity"
+ tools:deviceIds="wear">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:onClick="onClickEnablePermission"
+ android:orientation="vertical"
+ app:layout_box="all">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:paddingBottom="18dp"
+ android:textColor="#000000"
+ android:text="@string/calendar_permission_text"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <android.support.wearable.view.CircledImageView
+ android:id="@+id/circle"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ app:circle_radius="20dp"
+ app:circle_color="#0086D4"
+ android:src="@drawable/ic_lock_open_white_24dp"/>
+
+ <android.support.v4.widget.Space
+ android:layout_width="8dp"
+ android:layout_height="8dp"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:textColor="#0086D4"
+ android:text="Enable Permission"/>
+
+
+ </LinearLayout>
+
+ </LinearLayout>
+</android.support.wearable.view.BoxInsetLayout>
\ No newline at end of file
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml b/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml
index ed2f0a3..4090995 100644
--- a/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml
@@ -34,10 +34,13 @@
<string name="fit_distance">%1$,.2f meters</string>
<string name="calendar_name">Sample Calendar</string>
+ <string name="calendar_permission_not_approved"><br><br><br>WatchFace requires Calendar permission. Click on this WatchFace or visit Settings > Permissions to approve.</string>
<plurals name="calendar_meetings">
<item quantity="one"><br><br><br>You have <b>%1$d</b> meeting in the next 24 hours.</item>
<item quantity="other"><br><br><br>You have <b>%1$d</b> meetings in the next 24 hours.</item>
</plurals>
+ <string name="title_activity_calendar_watch_face_permission">Calendar Permission Activity</string>
+ <string name="calendar_permission_text">WatchFace requires Calendar access.</string>
<!-- TODO: this should be shared (needs covering all the samples with Gradle build model) -->
<string name="color_black">Black</string>
diff --git a/wearable/wear/WatchFace/template-params.xml b/wearable/wear/WatchFace/template-params.xml
index 3c8b72b..15df71a 100644
--- a/wearable/wear/WatchFace/template-params.xml
+++ b/wearable/wear/WatchFace/template-params.xml
@@ -24,12 +24,12 @@
<minSdk>18</minSdk>
<targetSdkVersion>23</targetSdkVersion>
- <targetSdkVersionWear>22</targetSdkVersionWear>
+ <targetSdkVersionWear>23</targetSdkVersionWear>
<dependency_wearable>com.android.support:palette-v7:23.1.0</dependency_wearable>
<dependency>com.google.android.support:wearable:1.3.0</dependency>
- <dependency>com.google.android.gms:play-services-fitness:8.1.0</dependency>
- <dependency_wearable>com.google.android.gms:play-services-fitness:8.1.0</dependency_wearable>
+ <dependency>com.google.android.gms:play-services-fitness:8.3.0</dependency>
+ <dependency_wearable>com.google.android.gms:play-services-fitness:8.3.0</dependency_wearable>
<wearable>
<has_handheld_app>true</has_handheld_app>