diff options
author | Yorke Lee <yorkelee@google.com> | 2015-05-19 15:51:01 -0700 |
---|---|---|
committer | Yorke Lee <yorkelee@google.com> | 2015-05-22 11:40:21 -0700 |
commit | c16ea5ad67bf454158b364dec2f26c95a879c350 (patch) | |
tree | d711fcd0374d8d82102f81ad74d6f94cd75729d8 | |
parent | 5a194cd1f573d6c94a6b0e3e14cfabd69e42b856 (diff) |
Handle runtime permissions in Dialer
Conditionally disable the following features if the required
permissions are not available:
1) Display of all contacts
2) Display of speed dial
3) Caller ID in call log
4) Import/export contacts
5) Conversion of People.CONTENT_ITEM_TYPE and Phones.CONTENT_ITEM_TYPE
into a phone number (via DIAL intent)
6) UndemoteOutgoingCallReceiver
7) Contact Search
8) Contact lookup in call detail activity
9) Nearby places search
Bug: 20266292
Change-Id: I6d26902acb0eac407ae7bc18c11aa6ec57299506
13 files changed, 124 insertions, 28 deletions
diff --git a/src/com/android/dialer/DialerApplication.java b/src/com/android/dialer/DialerApplication.java index 7bc3bb4d3..b177d8336 100644 --- a/src/com/android/dialer/DialerApplication.java +++ b/src/com/android/dialer/DialerApplication.java @@ -19,14 +19,12 @@ package com.android.dialer; import android.app.Application; import android.os.Trace; -import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.extensions.ExtensionsFactory; import com.android.contacts.commonbind.analytics.AnalyticsUtil; public class DialerApplication extends Application { private static final String TAG = "DialerApplication"; - private ContactPhotoManager mContactPhotoManager; @Override public void onCreate() { diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index 56d5ad171..e240cf0aa 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -29,12 +29,10 @@ import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.os.Trace; -import android.provider.ContactsContract.Intents; import android.speech.RecognizerIntent; import android.support.v4.view.ViewPager; import android.telecom.PhoneAccount; import android.telecom.TelecomManager; -import android.telephony.TelephonyManager; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -63,6 +61,7 @@ import com.android.contacts.common.dialog.ClearFrequentsDialog; import com.android.contacts.common.interactions.ImportExportDialogFragment; import com.android.contacts.common.interactions.TouchPointManager; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.widget.FloatingActionButtonController; import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.calllog.CallLogActivity; @@ -248,11 +247,16 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O @Override public void show() { + final boolean hasContactsPermission = + PermissionsUtil.hasContactsPermissions(DialtactsActivity.this); final Menu menu = getMenu(); final MenuItem clearFrequents = menu.findItem(R.id.menu_clear_frequents); clearFrequents.setVisible(mListsFragment != null && mListsFragment.getSpeedDialFragment() != null && - mListsFragment.getSpeedDialFragment().hasFrequents()); + mListsFragment.getSpeedDialFragment().hasFrequents() && hasContactsPermission); + + menu.findItem(R.id.menu_import_export).setVisible(hasContactsPermission); + menu.findItem(R.id.menu_add_contact).setVisible(hasContactsPermission); super.show(); } } @@ -359,6 +363,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O protected void onCreate(Bundle savedInstanceState) { Trace.beginSection(TAG + " onCreate"); super.onCreate(savedInstanceState); + mFirstLaunch = true; final Resources resources = getResources(); @@ -818,7 +823,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O protected OptionsPopupMenu buildOptionsMenu(View invoker) { final OptionsPopupMenu popupMenu = new OptionsPopupMenu(this, invoker); popupMenu.inflate(R.menu.dialtacts_options); - final Menu menu = popupMenu.getMenu(); popupMenu.setOnMenuItemClickListener(this); return popupMenu; } @@ -829,7 +833,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mSearchView.setText(mPendingSearchViewQuery); mPendingSearchViewQuery = null; } - mActionBarController.restoreActionBarOffset(); + if (mActionBarController != null) { + mActionBarController.restoreActionBarOffset(); + } return false; } diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index 608475e0b..5c57c1854 100644 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -34,6 +34,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; +import com.android.contacts.common.util.PermissionsUtil; import com.android.dialer.PhoneCallDetails; import com.android.dialer.PhoneCallDetailsHelper; import com.android.dialer.R; @@ -184,8 +185,9 @@ public class CallLogAdapter extends GroupingListAdapter public boolean onPreDraw() { // We only wanted to listen for the first draw (and this is it). unregisterPreDrawListener(); - - mContactInfoCache.start(); + if (PermissionsUtil.hasContactsPermissions(mContext)) { + mContactInfoCache.start(); + } return true; } @@ -205,6 +207,9 @@ public class CallLogAdapter extends GroupingListAdapter mContactInfoCache = new ContactInfoCache( mContactInfoHelper, mOnContactInfoChangedListener); + if (!PermissionsUtil.hasContactsPermissions(context)) { + mContactInfoCache.disableRequestProcessing(); + } Resources resources = mContext.getResources(); CallTypeHelper callTypeHelper = new CallTypeHelper(resources); @@ -534,7 +539,7 @@ public class CallLogAdapter extends GroupingListAdapter @VisibleForTesting void disableRequestProcessingForTest() { // TODO: Remove this and test the cache directly. - mContactInfoCache.disableRequestProcessingForTest(); + mContactInfoCache.disableRequestProcessing(); } @VisibleForTesting diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java index 38c9bba87..9a660e1ae 100644 --- a/src/com/android/dialer/calllog/ContactInfoHelper.java +++ b/src/com/android/dialer/calllog/ContactInfoHelper.java @@ -30,6 +30,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.contacts.common.util.Constants; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.PhoneNumberHelper; import com.android.contacts.common.util.UriUtils; import com.android.dialer.service.CachedNumberLookupService; @@ -162,6 +163,9 @@ public class ContactInfoHelper { if (uri == null) { return null; } + if (!PermissionsUtil.hasContactsPermissions(mContext)) { + return ContactInfo.EMPTY; + } final ContactInfo info; Cursor phonesCursor = mContext.getContentResolver().query(uri, PhoneQuery._PROJECTION, null, null, null); diff --git a/src/com/android/dialer/contactinfo/ContactInfoCache.java b/src/com/android/dialer/contactinfo/ContactInfoCache.java index 2bb0f1e95..568f48886 100644 --- a/src/com/android/dialer/contactinfo/ContactInfoCache.java +++ b/src/com/android/dialer/contactinfo/ContactInfoCache.java @@ -51,7 +51,7 @@ public class ContactInfoCache { private volatile boolean mDone = false; public QueryThread() { - super("CallLogAdapter.QueryThread"); + super("ContactInfoCache.QueryThread"); } public void stopProcessing() { @@ -316,20 +316,12 @@ public class ContactInfoCache { && TextUtils.equals(callLogInfo.label, info.label); } - /** - * Can be set to true by tests to disable processing of requests. - */ - @VisibleForTesting private volatile boolean mRequestProcessingDisabled = false; /** * Sets whether processing of requests for contact details should be enabled. - * - * This method should be called in tests to disable such processing of requests when not - * needed. */ - @VisibleForTesting - public void disableRequestProcessingForTest() { + public void disableRequestProcessing() { mRequestProcessingDisabled = true; } diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java index 2177878c6..eec24f5bc 100644 --- a/src/com/android/dialer/database/DialerDatabaseHelper.java +++ b/src/com/android/dialer/database/DialerDatabaseHelper.java @@ -36,6 +36,7 @@ import android.provider.ContactsContract.Directory; import android.text.TextUtils; import android.util.Log; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.StopWatch; import com.android.dialer.R; import com.android.dialer.dialpad.SmartDialNameMatcher; @@ -485,7 +486,9 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { * Starts the database upgrade process in the background. */ public void startSmartDialUpdateThread() { - new SmartDialUpdateAsyncTask().execute(); + if (PermissionsUtil.hasContactsPermissions(mContext)) { + new SmartDialUpdateAsyncTask().execute(); + } } private class SmartDialUpdateAsyncTask extends AsyncTask { diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index 8d27c143b..de1d44f89 100644 --- a/src/com/android/dialer/dialpad/DialpadFragment.java +++ b/src/com/android/dialer/dialpad/DialpadFragment.java @@ -70,6 +70,7 @@ import android.widget.TextView; import com.android.contacts.common.ContactsUtils; import com.android.contacts.common.GeoUtil; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.PhoneNumberFormatter; import com.android.contacts.common.util.StopWatch; import com.android.contacts.common.widget.FloatingActionButtonController; @@ -441,6 +442,9 @@ public class DialpadFragment extends Fragment setFormattedDigits(converted, null); return true; } else { + if (!PermissionsUtil.hasContactsPermissions(getActivity())) { + return false; + } String type = intent.getType(); if (People.CONTENT_ITEM_TYPE.equals(type) || Phones.CONTENT_ITEM_TYPE.equals(type)) { diff --git a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java index 372692eae..f83f18cd7 100644 --- a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java +++ b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java @@ -25,6 +25,7 @@ import android.net.Uri; import android.util.Log; import com.android.contacts.common.list.PhoneNumberListAdapter.PhoneQuery; +import com.android.contacts.common.util.PermissionsUtil; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.database.DialerDatabaseHelper.ContactNumber; import com.android.dialerbind.DatabaseHelperManager; @@ -77,6 +78,10 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> { Log.v(TAG, "Load in background " + mQuery); } + if (!PermissionsUtil.hasContactsPermissions(mContext)) { + return new MatrixCursor(PhoneQuery.PROJECTION_PRIMARY); + } + /** Loads results from the database helper. */ final DialerDatabaseHelper dialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper( mContext); diff --git a/src/com/android/dialer/interactions/UndemoteOutgoingCallReceiver.java b/src/com/android/dialer/interactions/UndemoteOutgoingCallReceiver.java index 960a31bc3..fd3d512f0 100644 --- a/src/com/android/dialer/interactions/UndemoteOutgoingCallReceiver.java +++ b/src/com/android/dialer/interactions/UndemoteOutgoingCallReceiver.java @@ -27,6 +27,8 @@ import android.provider.ContactsContract.PhoneLookup; import android.provider.ContactsContract.PinnedPositions; import android.text.TextUtils; +import com.android.contacts.common.util.PermissionsUtil; + /** * This broadcast receiver is used to listen to outgoing calls and undemote formerly demoted * contacts if a phone call is made to a phone number belonging to that contact. @@ -39,12 +41,15 @@ public class UndemoteOutgoingCallReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { + if (!PermissionsUtil.hasContactsPermissions(context)) { + return; + } if (intent != null && Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) { final String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); if (TextUtils.isEmpty(number)) { return; } - final Thread thread = new Thread() { + new Thread() { @Override public void run() { final long id = getContactIdFromPhoneNumber(context, number); @@ -52,8 +57,7 @@ public class UndemoteOutgoingCallReceiver extends BroadcastReceiver { undemoteContactWithId(context, id); } } - }; - thread.start(); + }.start(); } } diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java index 94efc4869..eaa5cc808 100644 --- a/src/com/android/dialer/list/AllContactsFragment.java +++ b/src/com/android/dialer/list/AllContactsFragment.java @@ -29,6 +29,7 @@ import com.android.contacts.common.list.ContactEntryListAdapter; import com.android.contacts.common.list.ContactEntryListFragment; import com.android.contacts.common.list.ContactListFilter; import com.android.contacts.common.list.DefaultContactListAdapter; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.ViewUtil; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; @@ -60,7 +61,18 @@ public class AllContactsFragment extends ContactEntryListFragment<ContactEntryLi } @Override + protected void startLoading() { + if (PermissionsUtil.hasContactsPermissions(getActivity())) { + super.startLoading(); + } + } + + @Override protected ContactEntryListAdapter createListAdapter() { + if (!PermissionsUtil.hasContactsPermissions(getActivity())) { + return new EmptyContactsListAdapter(getActivity()); + } + final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) { @Override protected void bindView(View itemView, int partition, Cursor cursor, int position) { diff --git a/src/com/android/dialer/list/EmptyContactsListAdapter.java b/src/com/android/dialer/list/EmptyContactsListAdapter.java new file mode 100644 index 000000000..54bd4771f --- /dev/null +++ b/src/com/android/dialer/list/EmptyContactsListAdapter.java @@ -0,0 +1,47 @@ +/* + * 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.dialer.list; + +import android.content.Context; +import android.content.CursorLoader; + +import com.android.contacts.common.list.ContactEntryListAdapter; + +/** + * Used to display an empty contact list when we don't have the permissions to read contacts. + */ +public class EmptyContactsListAdapter extends ContactEntryListAdapter { + + public EmptyContactsListAdapter(Context context) { + super(context); + } + + @Override + public String getContactDisplayName(int position) { + return null; + } + + @Override + public void configureLoader(CursorLoader loader, long directoryId) { + loader.setUri(null); + } + + @Override + public int getCount() { + return 0; + } +} diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java index c314478ca..f86c0e5cf 100644 --- a/src/com/android/dialer/list/SearchFragment.java +++ b/src/com/android/dialer/list/SearchFragment.java @@ -37,6 +37,7 @@ import com.android.contacts.common.list.ContactEntryListAdapter; import com.android.contacts.common.list.ContactListItemView; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.contacts.common.list.PhoneNumberPickerFragment; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.ViewUtil; import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.dialpad.DialpadFragment.ErrorDialogFragment; @@ -287,4 +288,14 @@ public class SearchFragment extends PhoneNumberPickerFragment { listView.getPaddingEnd(), listView.getPaddingBottom()); } + + @Override + protected void startLoading() { + if (PermissionsUtil.hasContactsPermissions(getActivity())) { + super.startLoading(); + } else if (TextUtils.isEmpty(getQueryString())) { + // Clear out any existing call shortcuts. + getAdapter().setQueryString(null); + } + } } diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java index e72b25059..541cdf6e1 100644 --- a/src/com/android/dialer/list/SpeedDialFragment.java +++ b/src/com/android/dialer/list/SpeedDialFragment.java @@ -23,7 +23,6 @@ import android.app.Fragment; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Loader; -import android.content.res.Resources; import android.database.Cursor; import android.graphics.Rect; import android.net.Uri; @@ -43,12 +42,12 @@ import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import android.widget.ImageView; import android.widget.ListView; -import android.widget.RelativeLayout; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.ContactTileLoaderFactory; import com.android.contacts.common.list.ContactTileView; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; +import com.android.contacts.common.util.PermissionsUtil; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; @@ -194,7 +193,9 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, Trace.beginSection(TAG + " onResume"); super.onResume(); - getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad(); + if (PermissionsUtil.hasContactsPermissions(getActivity())) { + getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad(); + } Trace.endSection(); } @@ -286,7 +287,11 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, // Use initLoader() instead of restartLoader() to refraining unnecessary reload. // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will // be called, on which we'll check if "all" contacts should be reloaded again or not. - getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener); + if (PermissionsUtil.hasContactsPermissions(activity)) { + getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener); + } else { + setEmptyViewVisibility(true); + } } /** |