Handle some runtime permissions in ContactsCommon
Add utility methods to check if a permission group has been
granted at runtime.
Perform checks before executing certain functionality (CountryDetector,
Clear frequents dialog, preload of photos in ContactPhotoManager).
Bug: 20266292
Change-Id: I0dd3d82d69780b7d3243579eb5b09f96104c1c1f
diff --git a/src/com/android/contacts/common/ContactPhotoManager.java b/src/com/android/contacts/common/ContactPhotoManager.java
index 87ac044..dce6a77 100644
--- a/src/com/android/contacts/common/ContactPhotoManager.java
+++ b/src/com/android/contacts/common/ContactPhotoManager.java
@@ -56,6 +56,7 @@
import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.contacts.common.util.BitmapUtil;
+import com.android.contacts.common.util.PermissionsUtil;
import com.android.contacts.common.util.UriUtils;
import com.android.contacts.commonbind.util.UserAgentGenerator;
@@ -434,7 +435,9 @@
Context applicationContext = context.getApplicationContext();
sInstance = createContactPhotoManager(applicationContext);
applicationContext.registerComponentCallbacks(sInstance);
- sInstance.preloadPhotosInBackground();
+ if (PermissionsUtil.hasContactsPermissions(context)) {
+ sInstance.preloadPhotosInBackground();
+ }
}
return sInstance;
}
diff --git a/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java b/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java
index 2cfd36e..2fab3e1 100644
--- a/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java
+++ b/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java
@@ -21,6 +21,7 @@
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
@@ -28,6 +29,7 @@
import android.provider.ContactsContract;
import com.android.contacts.common.R;
+import com.android.contacts.common.util.PermissionsUtil;
/**
* Dialog that clears the frequently contacted list after confirming with the user.
@@ -41,10 +43,14 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity().getApplicationContext();
final ContentResolver resolver = getActivity().getContentResolver();
final OnClickListener okListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
+ if (!PermissionsUtil.hasContactsPermissions(context)) {
+ return;
+ }
final IndeterminateProgressDialog progressDialog = IndeterminateProgressDialog.show(
getFragmentManager(), getString(R.string.clearFrequentsProgress_title),
null, 500);
diff --git a/src/com/android/contacts/common/location/CountryDetector.java b/src/com/android/contacts/common/location/CountryDetector.java
index 7ad57d2..129effd 100644
--- a/src/com/android/contacts/common/location/CountryDetector.java
+++ b/src/com/android/contacts/common/location/CountryDetector.java
@@ -11,8 +11,10 @@
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Log;
import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.util.PermissionsUtil;
import java.util.Locale;
@@ -91,6 +93,11 @@
public static void registerForLocationUpdates(Context context,
LocationManager locationManager) {
+ if (!PermissionsUtil.hasLocationPermissions(context)) {
+ Log.w(TAG, "No location permissions, not registering for location updates.");
+ return;
+ }
+
if (!Geocoder.isPresent()) {
// Certain devices do not have an implementation of a geocoder - in that case there is
// no point trying to get location updates because we cannot retrieve the country based
@@ -158,7 +165,7 @@
* @return the geocoded country code detected by the {@link LocationManager}.
*/
private String getLocationBasedCountryIso() {
- if (!Geocoder.isPresent()) {
+ if (!Geocoder.isPresent() || !PermissionsUtil.hasLocationPermissions(mContext)) {
return null;
}
final SharedPreferences sharedPreferences =
diff --git a/src/com/android/contacts/common/util/PermissionsUtil.java b/src/com/android/contacts/common/util/PermissionsUtil.java
new file mode 100644
index 0000000..97f1cf6
--- /dev/null
+++ b/src/com/android/contacts/common/util/PermissionsUtil.java
@@ -0,0 +1,76 @@
+/*
+ * 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.android.contacts.common.util;
+
+import android.Manifest.permission;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * Utility class to help with runtime permissions.
+ */
+public class PermissionsUtil {
+ // Each permission in this list is a cherry-picked permission from a particular permission
+ // group. Granting a permission group enables access to all permissions in that group so we
+ // only need to check a single permission in each group.
+ // Note: This assumes that the app has correctly requested for all the relevant permissions
+ // in its Manifest file.
+ public static final String PHONE = permission.CALL_PHONE;
+ public static final String CONTACTS = permission.READ_CONTACTS;
+ public static final String LOCATION = permission.ACCESS_FINE_LOCATION;
+
+ private static Boolean sHasPhonePermissions;
+ private static Boolean sHasContactsPermissions;
+ private static Boolean sHasLocationPermissions;
+
+ public static boolean hasPhonePermissions(Context context) {
+ if (sHasPhonePermissions == null) {
+ sHasPhonePermissions = hasPermission(context, PHONE);
+ }
+ return sHasPhonePermissions;
+ }
+
+ public static boolean hasContactsPermissions(Context context) {
+ if (sHasContactsPermissions == null) {
+ sHasContactsPermissions = hasPermission(context, CONTACTS);
+ }
+ return sHasContactsPermissions;
+ }
+
+ public static boolean hasLocationPermissions(Context context) {
+ if (sHasLocationPermissions == null) {
+ sHasLocationPermissions = hasPermission(context, LOCATION);
+ }
+ return sHasLocationPermissions;
+ }
+
+ /**
+ * To be called during various activity lifecycle events to update the cached versions of the
+ * permissions.
+ *
+ * @param context A valid context.
+ */
+ public static void updateCachedPermissions(Context context) {
+ hasPermission(context, PHONE);
+ hasPermission(context, CONTACTS);
+ hasPermission(context, LOCATION);
+ }
+
+ public static boolean hasPermission(Context context, String permission) {
+ return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
+ }
+}