aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Koch <akoch@google.com>2015-09-22 06:03:46 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-09-22 06:03:46 +0000
commit1d1948e9152433a491780f085daded25f0b4ec3c (patch)
treecd3bb170261841769ae1b4073a3bb0713d7e2a7e
parent8799315b3b67c173c3903ceccf0abe0a4b1dc400 (diff)
parentab673fa191558ba46553ea446887c2490e5b54e2 (diff)
downloadandroid-1d1948e9152433a491780f085daded25f0b4ec3c.tar.gz
Merge "Update XYZTouristAttractions for M permissions + minor bug fixes" into mnc-docs
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/AndroidManifest.xml8
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/provider/TouristAttractions.java8
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java12
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListActivity.java73
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListFragment.java11
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/res/layout/activity_main.xml7
-rw-r--r--wearable/wear/XYZTouristAttractions/Application/src/main/res/values/strings.xml2
-rw-r--r--wearable/wear/XYZTouristAttractions/Shared/src/main/java/com/example/android/xyztouristattractions/common/Utils.java16
-rw-r--r--wearable/wear/XYZTouristAttractions/Wearable/src/main/AndroidManifest.xml6
-rw-r--r--wearable/wear/XYZTouristAttractions/Wearable/src/main/java/com/example/android/xyztouristattractions/service/ListenerService.java15
-rw-r--r--wearable/wear/XYZTouristAttractions/Wearable/src/main/res/layout/gridpager_action.xml2
-rw-r--r--wearable/wear/XYZTouristAttractions/template-params.xml13
12 files changed, 141 insertions, 32 deletions
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/AndroidManifest.xml b/wearable/wear/XYZTouristAttractions/Application/src/main/AndroidManifest.xml
index 76f0198d..9d88b398 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/AndroidManifest.xml
@@ -16,17 +16,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.xyztouristattractions" >
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example.android.xyztouristattractions">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/XYZAppTheme" >
+ android:theme="@style/XYZAppTheme"
+ android:fullBackupContent="true">
<activity
android:name=".ui.AttractionListActivity"
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/provider/TouristAttractions.java b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/provider/TouristAttractions.java
index 50be3626..62ddbf9a 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/provider/TouristAttractions.java
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/provider/TouristAttractions.java
@@ -18,7 +18,6 @@ package com.example.android.xyztouristattractions.provider;
import android.net.Uri;
-import com.example.android.xyztouristattractions.BuildConfig;
import com.example.android.xyztouristattractions.common.Attraction;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.maps.model.LatLng;
@@ -126,11 +125,8 @@ public class TouristAttractions {
public static String getClosestCity(LatLng curLatLng) {
if (curLatLng == null) {
- // In debug build still return a city so some data is displayed
- if (BuildConfig.DEBUG) {
- return TEST_CITY;
- }
- return null;
+ // If location is unknown return test city so some data is shown
+ return TEST_CITY;
}
double minDistance = 0;
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
index 4112a656..48bad2c6 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
@@ -150,6 +150,11 @@ public class UtilityService extends IntentService {
*/
private void addGeofencesInternal() {
Log.v(TAG, ACTION_ADD_GEOFENCES);
+
+ if (!Utils.checkFineLocationPermission(this)) {
+ return;
+ }
+
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.build();
@@ -202,6 +207,11 @@ public class UtilityService extends IntentService {
*/
private void requestLocationInternal() {
Log.v(TAG, ACTION_REQUEST_LOCATION);
+
+ if (!Utils.checkFineLocationPermission(this)) {
+ return;
+ }
+
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.build();
@@ -358,7 +368,7 @@ public class UtilityService extends IntentService {
.setSmallIcon(R.drawable.ic_stat_maps_pin_drop)
.setContentIntent(pendingIntent)
.setDeleteIntent(deletePendingIntent)
- .setColor(getResources().getColor(R.color.colorPrimary))
+ .setColor(getResources().getColor(R.color.colorPrimary, getTheme()))
.setCategory(Notification.CATEGORY_RECOMMENDATION)
.setAutoCancel(true);
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListActivity.java b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListActivity.java
index 8d2908c2..8c23f3dd 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListActivity.java
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListActivity.java
@@ -16,11 +16,16 @@
package com.example.android.xyztouristattractions.ui;
+import android.Manifest;
+import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.View;
import android.widget.Toast;
import com.example.android.xyztouristattractions.R;
@@ -31,7 +36,10 @@ import com.example.android.xyztouristattractions.service.UtilityService;
* The main tourist attraction activity screen which contains a list of
* attractions sorted by distance.
*/
-public class AttractionListActivity extends AppCompatActivity {
+public class AttractionListActivity extends AppCompatActivity implements
+ ActivityCompat.OnRequestPermissionsResultCallback {
+
+ private static final int PERMISSION_REQ = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -44,7 +52,23 @@ public class AttractionListActivity extends AppCompatActivity {
.commit();
}
- UtilityService.addGeofences(this);
+ // Check fine location permission has been granted
+ if (!Utils.checkFineLocationPermission(this)) {
+ // See if user has denied permission in the past
+ if (ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION)) {
+ // Show a simple snackbar explaining the request instead
+ showPermissionSnackbar();
+ } else {
+ // Otherwise request permission from user
+ if (savedInstanceState == null) {
+ requestFineLocationPermission();
+ }
+ }
+ } else {
+ // Otherwise permission is granted (which is always the case on pre-M devices)
+ fineLocationPermissionGranted();
+ }
}
@Override
@@ -88,6 +112,51 @@ public class AttractionListActivity extends AppCompatActivity {
}
/**
+ * Permissions request result callback
+ */
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, String[] permissions, int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSION_REQ:
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ fineLocationPermissionGranted();
+ }
+ }
+ }
+
+ /**
+ * Request the fine location permission from the user
+ */
+ private void requestFineLocationPermission() {
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQ);
+ }
+
+ /**
+ * Run when fine location permission has been granted
+ */
+ private void fineLocationPermissionGranted() {
+ UtilityService.addGeofences(this);
+ UtilityService.requestLocation(this);
+ }
+
+ /**
+ * Show a permission explanation snackbar
+ */
+ private void showPermissionSnackbar() {
+ Snackbar.make(
+ findViewById(R.id.container), R.string.permission_explanation, Snackbar.LENGTH_LONG)
+ .setAction(R.string.permission_explanation_action, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ requestFineLocationPermission();
+ }
+ })
+ .show();
+ }
+
+ /**
* Show a basic debug dialog to provide more info on the built-in debug
* options.
*/
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListFragment.java b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListFragment.java
index e86ac3f9..71439b14 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListFragment.java
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/ui/AttractionListFragment.java
@@ -59,6 +59,7 @@ public class AttractionListFragment extends Fragment {
private AttractionAdapter mAdapter;
private LatLng mLatestLocation;
private int mImageSize;
+ private boolean mItemClicked;
public AttractionListFragment() {}
@@ -86,6 +87,7 @@ public class AttractionListFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
+ mItemClicked = false;
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mBroadcastReceiver, UtilityService.getLocationUpdatedIntentFilter());
}
@@ -186,9 +188,12 @@ public class AttractionListFragment extends Fragment {
@Override
public void onItemClick(View view, int position) {
- View heroView = view.findViewById(android.R.id.icon);
- DetailActivity.launch(
- getActivity(), mAdapter.mAttractionList.get(position).name, heroView);
+ if (!mItemClicked) {
+ mItemClicked = true;
+ View heroView = view.findViewById(android.R.id.icon);
+ DetailActivity.launch(
+ getActivity(), mAdapter.mAttractionList.get(position).name, heroView);
+ }
}
}
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/res/layout/activity_main.xml b/wearable/wear/XYZTouristAttractions/Application/src/main/res/layout/activity_main.xml
index 86616102..17c9f66e 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/res/layout/activity_main.xml
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/res/layout/activity_main.xml
@@ -14,12 +14,13 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
tools:context=".MainActivity">
-</LinearLayout> \ No newline at end of file
+</android.support.design.widget.CoordinatorLayout> \ No newline at end of file
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/res/values/strings.xml b/wearable/wear/XYZTouristAttractions/Application/src/main/res/values/strings.xml
index 5f3ee145..fede01e8 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/res/values/strings.xml
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/res/values/strings.xml
@@ -45,5 +45,7 @@ appear further down your stream
</string>
<string name="action_test_toggle_geofence">Toggle Geofence Trigger</string>
<string name="action_map">Show on Map</string>
+ <string name="permission_explanation">Allow this app to use your location to show distance to attractions?</string>
+ <string name="permission_explanation_action">Let\'s do it!</string>
</resources>
diff --git a/wearable/wear/XYZTouristAttractions/Shared/src/main/java/com/example/android/xyztouristattractions/common/Utils.java b/wearable/wear/XYZTouristAttractions/Shared/src/main/java/com/example/android/xyztouristattractions/common/Utils.java
index 70e05bf2..6fa51299 100644
--- a/wearable/wear/XYZTouristAttractions/Shared/src/main/java/com/example/android/xyztouristattractions/common/Utils.java
+++ b/wearable/wear/XYZTouristAttractions/Shared/src/main/java/com/example/android/xyztouristattractions/common/Utils.java
@@ -16,13 +16,16 @@
package com.example.android.xyztouristattractions.common;
+import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.graphics.Rect;
import android.preference.PreferenceManager;
+import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Display;
@@ -54,6 +57,15 @@ public class Utils {
private static final String DISTANCE_M_POSTFIX = "m";
/**
+ * Check if the app has access to fine location permission. On pre-M
+ * devices this will always return true.
+ */
+ public static boolean checkFineLocationPermission(Context context) {
+ return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
+ context, Manifest.permission.ACCESS_FINE_LOCATION);
+ }
+
+ /**
* Calculate distance between two LatLng points and format it nicely for
* display. As this is a sample, it only statically supports metric units.
* A production app should check locale and support the correct units.
@@ -90,6 +102,10 @@ public class Utils {
* Fetch the location from app preferences.
*/
public static LatLng getLocation(Context context) {
+ if (!checkFineLocationPermission(context)) {
+ return null;
+ }
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Long lat = prefs.getLong(PREFERENCES_LAT, Long.MAX_VALUE);
Long lng = prefs.getLong(PREFERENCES_LNG, Long.MAX_VALUE);
diff --git a/wearable/wear/XYZTouristAttractions/Wearable/src/main/AndroidManifest.xml b/wearable/wear/XYZTouristAttractions/Wearable/src/main/AndroidManifest.xml
index 80d0c920..d353b290 100644
--- a/wearable/wear/XYZTouristAttractions/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/XYZTouristAttractions/Wearable/src/main/AndroidManifest.xml
@@ -16,10 +16,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.xyztouristattractions" >
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example.android.xyztouristattractions">
<uses-feature android:name="android.hardware.type.watch" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
+
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="22" />
diff --git a/wearable/wear/XYZTouristAttractions/Wearable/src/main/java/com/example/android/xyztouristattractions/service/ListenerService.java b/wearable/wear/XYZTouristAttractions/Wearable/src/main/java/com/example/android/xyztouristattractions/service/ListenerService.java
index d2282511..ea071f05 100644
--- a/wearable/wear/XYZTouristAttractions/Wearable/src/main/java/com/example/android/xyztouristattractions/service/ListenerService.java
+++ b/wearable/wear/XYZTouristAttractions/Wearable/src/main/java/com/example/android/xyztouristattractions/service/ListenerService.java
@@ -17,11 +17,12 @@
package com.example.android.xyztouristattractions.service;
import android.app.Notification;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
import com.example.android.xyztouristattractions.R;
@@ -39,7 +40,6 @@ import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;
import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -106,21 +106,20 @@ public class ListenerService extends WearableListenerService {
PendingIntent deletePendingIntent = PendingIntent.getService(
this, 0, UtilityService.getClearRemoteNotificationsIntent(this), 0);
- Notification notification = new Notification.Builder(this)
+ Notification notification = new NotificationCompat.Builder(this)
.setContentText(getResources().getQuantityString(
R.plurals.attractions_found, count, count))
.setSmallIcon(R.mipmap.ic_launcher)
.setDeleteIntent(deletePendingIntent)
- .addAction(R.drawable.ic_full_explore,
+ .addAction(new NotificationCompat.Action.Builder(R.drawable.ic_full_explore,
getString(R.string.action_explore),
- pendingIntent)
- .extend(new Notification.WearableExtender()
+ pendingIntent).build())
+ .extend(new NotificationCompat.WearableExtender()
.setBackground(bitmap)
)
.build();
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(Constants.WEAR_NOTIFICATION_ID, notification);
googleApiClient.disconnect();
diff --git a/wearable/wear/XYZTouristAttractions/Wearable/src/main/res/layout/gridpager_action.xml b/wearable/wear/XYZTouristAttractions/Wearable/src/main/res/layout/gridpager_action.xml
index ac01509f..45495ad6 100644
--- a/wearable/wear/XYZTouristAttractions/Wearable/src/main/res/layout/gridpager_action.xml
+++ b/wearable/wear/XYZTouristAttractions/Wearable/src/main/res/layout/gridpager_action.xml
@@ -26,4 +26,4 @@
android:text="@string/action_open"
android:maxLines="1"
android:color="@color/colorPrimary"
- app:rippleColor="@color/colorAccent" />
+ app:buttonRippleColor="@color/colorAccent" />
diff --git a/wearable/wear/XYZTouristAttractions/template-params.xml b/wearable/wear/XYZTouristAttractions/template-params.xml
index cfa368f9..473b1110 100644
--- a/wearable/wear/XYZTouristAttractions/template-params.xml
+++ b/wearable/wear/XYZTouristAttractions/template-params.xml
@@ -19,7 +19,7 @@
<group>Wearable</group>
<package>com.example.android.xyztouristattractions</package>
<minSdk>18</minSdk>
- <targetSdkVersion>22</targetSdkVersion>
+ <targetSdkVersion>23</targetSdkVersion>
<wearable>
<has_handheld_app>true</has_handheld_app>
@@ -27,11 +27,12 @@
<dependency>com.google.android.gms:play-services-location</dependency>
<dependency>com.google.maps.android:android-maps-utils:0.3.4</dependency>
- <dependency>com.github.bumptech.glide:glide:3.6.0</dependency>
- <dependency>com.android.support:appcompat-v7:22.2.0</dependency>
- <dependency>com.android.support:recyclerview-v7:22.2.0</dependency>
- <dependency>com.android.support:design:22.2.0</dependency>
+ <dependency>com.github.bumptech.glide:glide:3.6.1</dependency>
+ <dependency>com.android.support:appcompat-v7:23.0.0</dependency>
+ <dependency>com.android.support:recyclerview-v7:23.0.0</dependency>
+ <dependency>com.android.support:design:23.0.0</dependency>
<dependency_wearable>com.google.android.gms:play-services-location</dependency_wearable>
+ <dependency_shared>com.android.support:support-v13:23.0.0</dependency_shared>
<dependency_shared>com.google.android.gms:play-services-wearable</dependency_shared>
<dependency_shared>com.google.android.gms:play-services-location</dependency_shared>
<dependency_shared>com.google.maps.android:android-maps-utils:0.3.4</dependency_shared>
@@ -83,6 +84,8 @@ attractions in a GridViewPager UI component.
<android>android.support.v7.appcompat</android>
<android>android.support.v7.widget.RecyclerView</android>
<android>android.support.v7.widget.GridLayoutManager</android>
+ <android>android.support.v4.content.ContextCompat</android>
+ <android>android.support.v4.app.ActivityCompat</android>
<android>android.support.design.widget.FloatingActionButton</android>
<android>android.support.design.widget.CoordinatorLayout</android>
<android>com.google.android.gms.common.api.GoogleApiClient</android>