Handle runtime permissions

For now, we handle runtime permissions in the most
hamfisted and maintainable way possible: don't let
any Activity's be fully created unless we get all the
runtime permissions.

Bug: 20066216
Change-Id: Iaab9ad2a8106d34b5e20a1eae1ef7a5560dc49a2
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b8741d2..0bb4b07 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,6 +20,8 @@
 
     <original-package android:name="com.android.contacts" />
 
+    <!-- Whenever a permission is added here, it should also be added to
+         RequestPermissionsActivity so it can be requested at runtime. -->
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
@@ -44,6 +46,7 @@
     <uses-permission android:name="android.permission.READ_CALL_LOG" />
     <uses-permission android:name="android.permission.READ_SMS" />
     <uses-permission android:name="android.permission.READ_CALENDAR" />
+    <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" />
 
     <application
         android:name="com.android.contacts.ContactsApplication"
@@ -215,6 +218,12 @@
             android:theme="@style/ContactListFilterTheme" />
 
         <activity
+            android:name=".common.activity.RequestPermissionsActivity"
+            android:label="@string/launcherActivityLabel"
+            android:theme="@style/PeopleTheme"
+            android:exported="false"/>
+
+        <activity
             android:name=".activities.ShowOrCreateActivity"
             android:label="@string/launcherActivityLabel"
             android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar">
@@ -322,6 +331,29 @@
             android:windowSoftInputMode="adjustResize"
             android:exported="false"/>
 
+        <!-- Edit or create a contact with only the most important fields displayed initially. -->
+        <activity
+            android:name=".activities.CompactContactEditorActivity"
+            android:label="@string/launcherActivityLabel"
+            android:theme="@style/EditorActivityTheme"
+            android:windowSoftInputMode="stateHidden|adjustPan">
+
+            <intent-filter android:label="@string/editContactDescription">
+                <action android:name="android.intent.action.EDIT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.item/person" />
+                <data android:mimeType="vnd.android.cursor.item/contact" />
+                <data android:mimeType="vnd.android.cursor.item/raw_contact" />
+            </intent-filter>
+            <intent-filter android:label="@string/insertContactDescription">
+                <action android:name="android.intent.action.INSERT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/person" />
+                <data android:mimeType="vnd.android.cursor.dir/contact" />
+                <data android:mimeType="vnd.android.cursor.dir/raw_contact" />
+            </intent-filter>
+        </activity>
+
         <!-- Create a new or edit an existing contact -->
         <activity
             android:name=".activities.ContactEditorActivity"
diff --git a/src/com/android/contacts/NonPhoneActivity.java b/src/com/android/contacts/NonPhoneActivity.java
index 8ae96a2..05c556b 100644
--- a/src/com/android/contacts/NonPhoneActivity.java
+++ b/src/com/android/contacts/NonPhoneActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts;
 
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 
 import android.app.Activity;
@@ -43,6 +44,10 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         final String phoneNumber = getPhoneNumber();
         if (TextUtils.isEmpty(phoneNumber)) {
             finish();
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 262c602..5573123 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -38,6 +38,7 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.model.Contact;
 import com.android.contacts.common.model.ContactLoader;
 import com.android.contacts.common.model.RawContactDelta;
@@ -85,6 +86,10 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         if (icicle != null) {
             final String uri = icicle.getString(KEY_CONTACT_URI);
             mContactUri = (uri == null) ? null : Uri.parse(uri);
diff --git a/src/com/android/contacts/activities/CompactContactEditorActivity.java b/src/com/android/contacts/activities/CompactContactEditorActivity.java
index 95cb08a..fcbb70e 100644
--- a/src/com/android/contacts/activities/CompactContactEditorActivity.java
+++ b/src/com/android/contacts/activities/CompactContactEditorActivity.java
@@ -18,6 +18,7 @@
 
 import com.android.contacts.R;
 import com.android.contacts.editor.CompactContactEditorFragment;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 
 import android.content.Intent;
 import android.net.Uri;
@@ -34,6 +35,10 @@
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         setContentView(R.layout.compact_contact_editor_activity);
 
         mFragment = (CompactContactEditorFragment) getFragmentManager().findFragmentByTag(
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index a0732aa..a9b75d9 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -17,6 +17,7 @@
 package com.android.contacts.activities;
 
 import com.android.contacts.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.editor.ContactEditorFragment;
 import com.android.contacts.util.DialogManager;
 
@@ -34,6 +35,10 @@
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         setContentView(R.layout.contact_editor_activity);
 
         mFragment = (ContactEditorFragment) getFragmentManager().findFragmentById(
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 0ba6e3a..e147b76 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -44,6 +44,7 @@
 
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.list.ContactEntryListFragment;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.list.ContactPickerFragment;
@@ -106,6 +107,10 @@
     protected void onCreate(Bundle savedState) {
         super.onCreate(savedState);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         if (savedState != null) {
             mActionCode = savedState.getInt(KEY_ACTION_CODE);
             mIsSearchMode = savedState.getBoolean(KEY_SEARCH_MODE);
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 6a5d348..83c4085 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -54,6 +54,7 @@
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter.TabState;
 import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.dialog.ClearFrequentsDialog;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.common.widget.FloatingActionButtonController;
@@ -225,6 +226,10 @@
         }
         super.onCreate(savedState);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         if (!processIntent(false)) {
             finish();
             return;
diff --git a/src/com/android/contacts/activities/ShowOrCreateActivity.java b/src/com/android/contacts/activities/ShowOrCreateActivity.java
index 8277cdd..6a516ad 100755
--- a/src/com/android/contacts/activities/ShowOrCreateActivity.java
+++ b/src/com/android/contacts/activities/ShowOrCreateActivity.java
@@ -37,6 +37,7 @@
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.util.NotifyingAsyncQueryHandler;
 
@@ -87,6 +88,10 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         // Create handler if doesn't exist, otherwise cancel any running
         if (mQueryHandler == null) {
             mQueryHandler = new NotifyingAsyncQueryHandler(this, this);
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 154968d..66bb473 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -96,6 +96,7 @@
 import com.android.contacts.common.ClipboardUtils;
 import com.android.contacts.common.Collapser;
 import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.editor.SelectAccountDialogFragment;
 import com.android.contacts.common.interactions.TouchPointManager;
 import com.android.contacts.common.lettertiles.LetterTileDrawable;
@@ -686,6 +687,10 @@
         Trace.beginSection("onCreate()");
         super.onCreate(savedInstanceState);
 
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
+
         getWindow().setStatusBarColor(Color.TRANSPARENT);
 
         processIntent(getIntent());
diff --git a/src/com/android/contacts/widget/PinnedHeaderListDemoActivity.java b/src/com/android/contacts/widget/PinnedHeaderListDemoActivity.java
index 027cc9d..bc9f07e 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListDemoActivity.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListDemoActivity.java
@@ -28,6 +28,7 @@
 import android.widget.TextView;
 
 import com.android.contacts.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.list.PinnedHeaderListAdapter;
 
 /**
@@ -98,6 +99,9 @@
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
+        if (RequestPermissionsActivity.startPermissionActivity(this)) {
+            return;
+        }
 
         setContentView(R.layout.pinned_header_list_demo);