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