Home | History | Annotate | Download | only in activity
      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 
     31 import java.util.ArrayList;
     32 import java.util.Arrays;
     33 
     34 /**
     35  * Activity that asks the user for all {@link #getDesiredPermissions} if any of
     36  * {@link #getRequiredPermissions} are missing.
     37  *
     38  * NOTE: As a result of b/22095159, this can behave oddly in the case where the final permission
     39  * you are requesting causes an application restart.
     40  */
     41 public abstract class RequestPermissionsActivityBase extends Activity
     42         implements ActivityCompat.OnRequestPermissionsResultCallback {
     43 
     44     public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";
     45 
     46     /** Whether the permissions activity was already started. */
     47     protected static final String STARTED_PERMISSIONS_ACTIVITY = "started_permissions_activity";
     48 
     49     private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;
     50 
     51     /**
     52      * @return list of permissions that are needed in order for {@link #PREVIOUS_ACTIVITY_INTENT} to
     53      * operate. You only need to return a single permission per permission group you care about.
     54      */
     55     protected abstract String[] getRequiredPermissions();
     56 
     57     /**
     58      * @return list of permissions that would be useful for {@link #PREVIOUS_ACTIVITY_INTENT} to
     59      * operate. You only need to return a single permission per permission group you care about.
     60      */
     61     protected abstract String[] getDesiredPermissions();
     62 
     63     protected Intent mPreviousActivityIntent;
     64 
     65     @Override
     66     protected void onCreate(Bundle savedInstanceState) {
     67         super.onCreate(savedInstanceState);
     68         mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
     69 
     70         // Only start a requestPermissions() flow when first starting this activity the first time.
     71         // The process is likely to be restarted during the permission flow (necessary to enable
     72         // permissions) so this is important to track.
     73         if (savedInstanceState == null) {
     74             requestPermissions();
     75         }
     76     }
     77 
     78     /**
     79      * If any permissions the Contacts app needs are missing, open an Activity
     80      * to prompt the user for these permissions. Moreover, finish the current activity.
     81      *
     82      * This is designed to be called inside {@link android.app.Activity#onCreate}
     83      */
     84     protected static boolean startPermissionActivity(Activity activity,
     85             String[] requiredPermissions, Class<?> newActivityClass) {
     86         if (!hasPermissions(activity, requiredPermissions)) {
     87             final Intent intent = new Intent(activity,  newActivityClass);
     88             activity.getIntent().putExtra(STARTED_PERMISSIONS_ACTIVITY, true);
     89             intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
     90             activity.startActivity(intent);
     91             activity.finish();
     92             return true;
     93         }
     94 
     95         // Account type initialization must be delayed until the Contacts permission group
     96         // has been granted (since GET_ACCOUNTS) falls under that groups.  Previously it
     97         // was initialized in ContactApplication which would cause problems as
     98         // AccountManager.getAccounts would return an empty array. See b/22690336
     99         AccountTypeManager.getInstance(activity);
    100 
    101         return false;
    102     }
    103 
    104     protected boolean isAllGranted(String permissions[], int[] grantResult) {
    105         for (int i = 0; i < permissions.length; i++) {
    106             if (grantResult[i] != PackageManager.PERMISSION_GRANTED
    107                     && isPermissionRequired(permissions[i])) {
    108                 return false;
    109             }
    110         }
    111         return true;
    112     }
    113 
    114     private boolean isPermissionRequired(String p) {
    115         return Arrays.asList(getRequiredPermissions()).contains(p);
    116     }
    117 
    118     private void requestPermissions() {
    119         Trace.beginSection("requestPermissions");
    120         try {
    121             // Construct a list of missing permissions
    122             final ArrayList<String> unsatisfiedPermissions = new ArrayList<>();
    123             for (String permission : getDesiredPermissions()) {
    124                 if (checkSelfPermission(permission)
    125                         != PackageManager.PERMISSION_GRANTED) {
    126                     unsatisfiedPermissions.add(permission);
    127                 }
    128             }
    129             if (unsatisfiedPermissions.size() == 0) {
    130                 throw new RuntimeException("Request permission activity was called even"
    131                         + " though all permissions are satisfied.");
    132             }
    133             ActivityCompat.requestPermissions(
    134                     this,
    135                     unsatisfiedPermissions.toArray(new String[unsatisfiedPermissions.size()]),
    136                     PERMISSIONS_REQUEST_ALL_PERMISSIONS);
    137         } finally {
    138             Trace.endSection();
    139         }
    140     }
    141 
    142     @Override
    143     public int checkSelfPermission(String permission) {
    144         return ContextCompat.checkSelfPermission(this, permission);
    145     }
    146 
    147     protected static boolean hasPermissions(Context context, String[] permissions) {
    148         Trace.beginSection("hasPermission");
    149         try {
    150             for (String permission : permissions) {
    151                 if (ContextCompat.checkSelfPermission(context, permission)
    152                         != PackageManager.PERMISSION_GRANTED) {
    153                     return false;
    154                 }
    155             }
    156             return true;
    157         } finally {
    158             Trace.endSection();
    159         }
    160     }
    161 }
    162