• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.contacts.common.activity;
18 
19 import com.android.contacts.common.R;
20 import com.android.contacts.common.model.AccountTypeManager;
21 
22 import android.app.Activity;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.os.Bundle;
27 import android.os.Trace;
28 import android.support.v4.app.ActivityCompat;
29 import android.support.v4.content.ContextCompat;
30 import android.widget.Toast;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 
35 /**
36  * Activity that asks the user for all {@link #getDesiredPermissions} if any of
37  * {@link #getRequiredPermissions} are missing.
38  *
39  * NOTE: As a result of b/22095159, this can behave oddly in the case where the final permission
40  * you are requesting causes an application restart.
41  */
42 public abstract class RequestPermissionsActivityBase extends Activity
43         implements ActivityCompat.OnRequestPermissionsResultCallback {
44 
45     public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";
46 
47     /** Whether the permissions activity was already started. */
48     protected static final String STARTED_PERMISSIONS_ACTIVITY = "started_permissions_activity";
49 
50     protected static final String EXTRA_IS_CALLER_SELF = "is_caller_self";
51 
52     private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;
53 
54     /**
55      * @return list of permissions that are needed in order for {@link #PREVIOUS_ACTIVITY_INTENT} to
56      * operate. You only need to return a single permission per permission group you care about.
57      */
getRequiredPermissions()58     protected abstract String[] getRequiredPermissions();
59 
60     /**
61      * @return list of permissions that would be useful for {@link #PREVIOUS_ACTIVITY_INTENT} to
62      * operate. You only need to return a single permission per permission group you care about.
63      */
getDesiredPermissions()64     protected abstract String[] getDesiredPermissions();
65 
66     protected Intent mPreviousActivityIntent;
67 
68     /** If true then start the target activity "for result" after permissions are granted. */
69     protected boolean mIsCallerSelf;
70 
71     @Override
onCreate(Bundle savedInstanceState)72     protected void onCreate(Bundle savedInstanceState) {
73         super.onCreate(savedInstanceState);
74         mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
75         mIsCallerSelf = getIntent().getBooleanExtra(EXTRA_IS_CALLER_SELF, false);
76 
77         // Only start a requestPermissions() flow when first starting this activity the first time.
78         // The process is likely to be restarted during the permission flow (necessary to enable
79         // permissions) so this is important to track.
80         if (savedInstanceState == null) {
81             requestPermissions();
82         }
83     }
84 
85     /**
86      * If any permissions the Contacts app needs are missing, open an Activity
87      * to prompt the user for these permissions. Moreover, finish the current activity.
88      *
89      * This is designed to be called inside {@link android.app.Activity#onCreate}
90      */
startPermissionActivity(Activity activity, String[] requiredPermissions, Class<?> newActivityClass)91     protected static boolean startPermissionActivity(Activity activity,
92             String[] requiredPermissions, Class<?> newActivityClass) {
93         return startPermissionActivity(activity, requiredPermissions, /* isCallerSelf */ false,
94                 newActivityClass);
95     }
96 
startPermissionActivity(Activity activity, String[] requiredPermissions, boolean isCallerSelf, Class<?> newActivityClass)97     protected static boolean startPermissionActivity(Activity activity,
98             String[] requiredPermissions, boolean isCallerSelf, Class<?> newActivityClass) {
99         if (!hasPermissions(activity, requiredPermissions)) {
100             final Intent intent = new Intent(activity,  newActivityClass);
101             activity.getIntent().putExtra(STARTED_PERMISSIONS_ACTIVITY, true);
102             intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
103             intent.putExtra(EXTRA_IS_CALLER_SELF, isCallerSelf);
104             activity.startActivity(intent);
105             activity.finish();
106             return true;
107         }
108 
109         // Account type initialization must be delayed until the Contacts permission group
110         // has been granted (since GET_ACCOUNTS) falls under that groups.  Previously it
111         // was initialized in ContactApplication which would cause problems as
112         // AccountManager.getAccounts would return an empty array. See b/22690336
113         AccountTypeManager.getInstance(activity);
114 
115         return false;
116     }
117 
isAllGranted(String permissions[], int[] grantResult)118     protected boolean isAllGranted(String permissions[], int[] grantResult) {
119         for (int i = 0; i < permissions.length; i++) {
120             if (grantResult[i] != PackageManager.PERMISSION_GRANTED
121                     && isPermissionRequired(permissions[i])) {
122                 return false;
123             }
124         }
125         return true;
126     }
127 
isPermissionRequired(String p)128     private boolean isPermissionRequired(String p) {
129         return Arrays.asList(getRequiredPermissions()).contains(p);
130     }
131 
requestPermissions()132     private void requestPermissions() {
133         Trace.beginSection("requestPermissions");
134         try {
135             // Construct a list of missing permissions
136             final ArrayList<String> unsatisfiedPermissions = new ArrayList<>();
137             for (String permission : getDesiredPermissions()) {
138                 if (checkSelfPermission(permission)
139                         != PackageManager.PERMISSION_GRANTED) {
140                     unsatisfiedPermissions.add(permission);
141                 }
142             }
143             if (unsatisfiedPermissions.size() == 0) {
144                 throw new RuntimeException("Request permission activity was called even"
145                         + " though all permissions are satisfied.");
146             }
147             ActivityCompat.requestPermissions(
148                     this,
149                     unsatisfiedPermissions.toArray(new String[unsatisfiedPermissions.size()]),
150                     PERMISSIONS_REQUEST_ALL_PERMISSIONS);
151         } finally {
152             Trace.endSection();
153         }
154     }
155 
156     @Override
checkSelfPermission(String permission)157     public int checkSelfPermission(String permission) {
158         return ContextCompat.checkSelfPermission(this, permission);
159     }
160 
hasPermissions(Context context, String[] permissions)161     protected static boolean hasPermissions(Context context, String[] permissions) {
162         Trace.beginSection("hasPermission");
163         try {
164             for (String permission : permissions) {
165                 if (ContextCompat.checkSelfPermission(context, permission)
166                         != PackageManager.PERMISSION_GRANTED) {
167                     return false;
168                 }
169             }
170             return true;
171         } finally {
172             Trace.endSection();
173         }
174     }
175 }
176