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.permissioncontroller.permission.ui;
18 
19 import static android.content.pm.PackageManager.PERMISSION_DENIED;
20 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
21 
22 import static com.android.permissioncontroller.PermissionControllerStatsLog.GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS;
23 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED;
24 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED;
25 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED;
26 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED;
27 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION;
28 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED;
29 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED;
30 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS;
31 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE;
32 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE_IN_SETTINGS;
33 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED;
34 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS;
35 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_ONE_TIME;
36 import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED;
37 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.CANCELED;
38 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED;
39 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN;
40 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS;
41 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_FOREGROUND_ONLY;
42 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ONE_TIME;
43 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.LINKED_TO_SETTINGS;
44 import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
45 import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED;
46 import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT;
47 import static com.android.permissioncontroller.permission.utils.Utils.getRequestMessage;
48 
49 import android.Manifest;
50 import android.app.Activity;
51 import android.app.KeyguardManager;
52 import android.app.admin.DevicePolicyManager;
53 import android.content.Intent;
54 import android.content.pm.PackageInfo;
55 import android.content.pm.PackageManager;
56 import android.content.pm.PackageManager.NameNotFoundException;
57 import android.content.res.Resources;
58 import android.graphics.drawable.Icon;
59 import android.os.Build;
60 import android.os.Bundle;
61 import android.os.UserHandle;
62 import android.permission.PermissionManager;
63 import android.text.Annotation;
64 import android.text.SpannableString;
65 import android.text.Spanned;
66 import android.text.style.ClickableSpan;
67 import android.util.ArrayMap;
68 import android.util.ArraySet;
69 import android.util.Log;
70 import android.util.Pair;
71 import android.view.MotionEvent;
72 import android.view.View;
73 import android.view.Window;
74 import android.view.WindowManager;
75 
76 import androidx.annotation.NonNull;
77 import androidx.annotation.Nullable;
78 import androidx.core.util.Consumer;
79 
80 import com.android.permissioncontroller.Constants;
81 import com.android.permissioncontroller.DeviceUtils;
82 import com.android.permissioncontroller.PermissionControllerStatsLog;
83 import com.android.permissioncontroller.R;
84 import com.android.permissioncontroller.permission.model.AppPermissionGroup;
85 import com.android.permissioncontroller.permission.model.AppPermissions;
86 import com.android.permissioncontroller.permission.model.Permission;
87 import com.android.permissioncontroller.permission.ui.auto.GrantPermissionsAutoViewHandler;
88 import com.android.permissioncontroller.permission.ui.wear.GrantPermissionsWearViewHandler;
89 import com.android.permissioncontroller.permission.utils.ArrayUtils;
90 import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor;
91 import com.android.permissioncontroller.permission.utils.SafetyNetLogger;
92 import com.android.permissioncontroller.permission.utils.Utils;
93 
94 import java.util.ArrayList;
95 import java.util.Collections;
96 import java.util.List;
97 import java.util.Random;
98 
99 public class GrantPermissionsActivity extends Activity
100         implements GrantPermissionsViewHandler.ResultListener {
101 
102     private static final String LOG_TAG = "GrantPermissionsActivity";
103 
104     private static final String KEY_REQUEST_ID = GrantPermissionsActivity.class.getName()
105             + "_REQUEST_ID";
106     public static final String ANNOTATION_ID = "link";
107 
108     public static final int NEXT_BUTTON = 11;
109     public static final int ALLOW_BUTTON = 0;
110     public static final int ALLOW_ALWAYS_BUTTON = 1;
111     public static final int ALLOW_FOREGROUND_BUTTON = 2;
112     public static final int DENY_BUTTON = 3;
113     public static final int DENY_AND_DONT_ASK_AGAIN_BUTTON = 4;
114     public static final int ALLOW_ONE_TIME_BUTTON = 5;
115     public static final int NO_UPGRADE_BUTTON = 6;
116     public static final int NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON = 7;
117     public static final int NO_UPGRADE_OT_BUTTON = 8; // one-time
118     public static final int NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON = 9; // one-time
119     public static final int LINK_TO_SETTINGS = 10;
120 
121     private static final int APP_PERMISSION_REQUEST_CODE = 1;
122 
123     /** Unique Id of a request */
124     private long mRequestId;
125 
126     private String[] mRequestedPermissions;
127     private boolean[] mButtonVisibilities;
128     private boolean mCouldHaveFgCapabilities;
129 
130     private ArrayMap<Pair<String, Boolean>, GroupState> mRequestGrantPermissionGroups =
131             new ArrayMap<>();
132     private ArraySet<String> mPermissionGroupsToSkip = new ArraySet<>();
133     private Consumer<Intent> mActivityResultCallback;
134 
135     private GrantPermissionsViewHandler mViewHandler;
136     private AppPermissions mAppPermissions;
137 
138     boolean mResultSet;
139 
140     /**
141      * Listens for changes to the permission of the app the permissions are currently getting
142      * granted to. {@code null} when unregistered.
143      */
144     private @Nullable PackageManager.OnPermissionsChangedListener mPermissionChangeListener;
145 
146     /**
147      * Listens for changes to the app the permissions are currently getting granted to. {@code null}
148      * when unregistered.
149      */
150     private @Nullable PackageRemovalMonitor mPackageRemovalMonitor;
151 
152     /** Package that requested the permission grant */
153     private String mCallingPackage;
154     /** uid of {@link #mCallingPackage} */
155     private int mCallingUid;
156     /** Notifier for auto-granted permissions */
157     private AutoGrantPermissionsNotifier mAutoGrantPermissionsNotifier;
158     private PackageInfo mCallingPackageInfo;
159 
getPermissionPolicy()160     private int getPermissionPolicy() {
161         DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
162         return devicePolicyManager.getPermissionPolicy(null);
163     }
164 
165     /**
166      * Try to add a single permission that is requested to be granted.
167      *
168      * <p>This does <u>not</u> expand the permissions into the {@link #computeAffectedPermissions
169      * affected permissions}.
170      *
171      * @param group The group the permission belongs to (might be a background permission group)
172      * @param permName The name of the permission to add
173      * @param isFirstInstance Is this the first time the groupStates get created
174      */
addRequestedPermissions(AppPermissionGroup group, String permName, boolean isFirstInstance)175     private void addRequestedPermissions(AppPermissionGroup group, String permName,
176             boolean isFirstInstance) {
177         if (!group.isGrantingAllowed()) {
178             reportRequestResult(permName,
179                     PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
180             // Skip showing groups that we know cannot be granted.
181             return;
182         }
183 
184         Permission permission = group.getPermission(permName);
185 
186         // If the permission is restricted it does not show in the UI and
187         // is not added to the group at all, so check that first.
188         if (permission == null && ArrayUtils.contains(
189                 mAppPermissions.getPackageInfo().requestedPermissions, permName)) {
190             reportRequestResult(permName,
191                   PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION);
192             return;
193         // We allow the user to choose only non-fixed permissions. A permission
194         // is fixed either by device policy or the user denying with prejudice.
195         } else if (group.isUserFixed()) {
196             reportRequestResult(permName,
197                     PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED);
198             return;
199         } else if (group.isPolicyFixed() && !group.areRuntimePermissionsGranted()
200                 || permission.isPolicyFixed()) {
201             reportRequestResult(permName,
202                     PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED);
203             return;
204         }
205 
206         Pair<String, Boolean> groupKey = new Pair<>(group.getName(),
207                 group.isBackgroundGroup());
208 
209         GroupState state = mRequestGrantPermissionGroups.get(groupKey);
210         if (state == null) {
211             state = new GroupState(group);
212             mRequestGrantPermissionGroups.put(groupKey, state);
213         }
214         state.affectedPermissions = ArrayUtils.appendString(
215                 state.affectedPermissions, permName);
216 
217         boolean skipGroup = false;
218         switch (getPermissionPolicy()) {
219             case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: {
220                 final String[] filterPermissions = new String[]{permName};
221                 group.grantRuntimePermissions(false, false, filterPermissions);
222                 group.setPolicyFixed(filterPermissions);
223                 state.mState = GroupState.STATE_ALLOWED;
224                 skipGroup = true;
225 
226                 getAutoGrantNotifier().onPermissionAutoGranted(permName);
227                 reportRequestResult(permName,
228                         PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED);
229             } break;
230 
231             case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: {
232                 final String[] filterPermissions = new String[]{permName};
233                 group.setPolicyFixed(filterPermissions);
234                 state.mState = GroupState.STATE_DENIED;
235                 skipGroup = true;
236 
237                 reportRequestResult(permName,
238                         PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED);
239             } break;
240 
241             default: {
242                 if (group.areRuntimePermissionsGranted()) {
243                     group.grantRuntimePermissions(false, false, new String[]{permName});
244                     state.mState = GroupState.STATE_ALLOWED;
245                     skipGroup = true;
246 
247                     reportRequestResult(permName,
248                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED);
249                 }
250             } break;
251         }
252 
253         if (skipGroup && isFirstInstance) {
254             // Only allow to skip groups when this is the first time the dialog was created.
255             // Otherwise the number of groups changes between instances of the dialog.
256             state.mState = GroupState.STATE_SKIPPED;
257         }
258     }
259 
260     /**
261      * Report the result of a grant of a permission.
262      *
263      * @param permission The permission that was granted or denied
264      * @param result The permission grant result
265      */
reportRequestResult(@onNull String permission, int result)266     private void reportRequestResult(@NonNull String permission, int result) {
267         boolean isImplicit = !ArrayUtils.contains(mRequestedPermissions, permission);
268 
269         Log.v(LOG_TAG,
270                 "Permission grant result requestId=" + mRequestId + " callingUid=" + mCallingUid
271                         + " callingPackage=" + mCallingPackage + " permission=" + permission
272                         + " isImplicit=" + isImplicit + " result=" + result);
273 
274         PermissionControllerStatsLog.write(
275                 PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED, mRequestId,
276                 mCallingUid, mCallingPackage, permission, isImplicit, result);
277     }
278 
279     /**
280      * Report the result of a grant of a permission.
281      *
282      * @param permissions The permissions that were granted or denied
283      * @param result The permission grant result
284      */
reportRequestResult(@onNull String[] permissions, int result)285     private void reportRequestResult(@NonNull String[] permissions, int result) {
286         for (String permission : permissions) {
287             reportRequestResult(permission, result);
288         }
289     }
290 
291     @Override
onCreate(Bundle icicle)292     public void onCreate(Bundle icicle) {
293         super.onCreate(icicle);
294 
295         if (icicle == null) {
296             mRequestId = new Random().nextLong();
297         } else {
298             mRequestId = icicle.getLong(KEY_REQUEST_ID);
299         }
300 
301         getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
302 
303         // Cache this as this can only read on onCreate, not later.
304         mCallingPackage = getCallingPackage();
305         try {
306             mCouldHaveFgCapabilities = Utils.couldHaveForegroundCapabilities(this, mCallingPackage);
307         } catch (NameNotFoundException e) {
308             Log.e(LOG_TAG, "Calling package " + mCallingPackage + " not found", e);
309         }
310 
311         setFinishOnTouchOutside(false);
312 
313         setTitle(R.string.permission_request_title);
314 
315         mRequestedPermissions = getIntent().getStringArrayExtra(
316                 PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
317         if (mRequestedPermissions == null) {
318             mRequestedPermissions = new String[0];
319         }
320 
321         final int requestedPermCount = mRequestedPermissions.length;
322 
323         if (requestedPermCount == 0) {
324             setResultAndFinish();
325             return;
326         }
327 
328         PackageInfo callingPackageInfo = getCallingPackageInfo();
329 
330         if (callingPackageInfo == null || callingPackageInfo.requestedPermissions == null
331                 || callingPackageInfo.requestedPermissions.length <= 0) {
332             setResultAndFinish();
333             return;
334         }
335 
336         // Don't allow legacy apps to request runtime permissions.
337         if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
338             // Returning empty arrays means a cancellation.
339             mRequestedPermissions = new String[0];
340             setResultAndFinish();
341             return;
342         }
343 
344         mCallingPackageInfo = callingPackageInfo;
345 
346         mCallingUid = callingPackageInfo.applicationInfo.uid;
347 
348         UserHandle userHandle = UserHandle.getUserHandleForUid(mCallingUid);
349 
350         if (DeviceUtils.isTelevision(this)) {
351             mViewHandler = new com.android.permissioncontroller.permission.ui.television
352                     .GrantPermissionsViewHandlerImpl(this,
353                     mCallingPackage).setResultListener(this);
354         } else if (DeviceUtils.isWear(this)) {
355             mViewHandler = new GrantPermissionsWearViewHandler(this).setResultListener(this);
356         } else if (DeviceUtils.isAuto(this)) {
357             mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage)
358                     .setResultListener(this);
359         } else {
360             mViewHandler = new com.android.permissioncontroller.permission.ui.handheld
361                     .GrantPermissionsViewHandlerImpl(this, mCallingPackage, userHandle)
362                     .setResultListener(this);
363         }
364 
365         mAppPermissions = new AppPermissions(this, callingPackageInfo, false,
366                 new Runnable() {
367                     @Override
368                     public void run() {
369                         setResultAndFinish();
370                     }
371                 });
372 
373         for (String requestedPermission : mRequestedPermissions) {
374             if (requestedPermission == null) {
375                 continue;
376             }
377 
378             ArrayList<String> affectedPermissions =
379                     computeAffectedPermissions(requestedPermission);
380 
381             int numAffectedPermissions = affectedPermissions.size();
382             for (int i = 0; i < numAffectedPermissions; i++) {
383                 AppPermissionGroup group =
384                         mAppPermissions.getGroupForPermission(affectedPermissions.get(i));
385                 if (group == null) {
386                     reportRequestResult(affectedPermissions.get(i),
387                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
388 
389                     continue;
390                 }
391 
392                 if (mAppPermissions.getPackageInfo().applicationInfo.targetSdkVersion
393                         >= Build.VERSION_CODES.R && mRequestedPermissions.length > 1
394                         && group.isBackgroundGroup()) {
395                     Log.e(LOG_TAG, "Apps targeting " + Build.VERSION_CODES.R + " must"
396                             + " have foreground permission before requesting background and must"
397                             + " request background on its own.");
398                     finish();
399                 }
400 
401                 addRequestedPermissions(group, affectedPermissions.get(i), icicle == null);
402             }
403         }
404 
405         int numGroupStates = mRequestGrantPermissionGroups.size();
406         for (int groupStateNum = 0; groupStateNum < numGroupStates; groupStateNum++) {
407             GroupState groupState = mRequestGrantPermissionGroups.valueAt(groupStateNum);
408             AppPermissionGroup group = groupState.mGroup;
409 
410             // Restore permission group state after lifecycle events
411             if (icicle != null) {
412                 groupState.mState = icicle.getInt(
413                         getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(groupStateNum)),
414                         groupState.mState);
415             }
416 
417             // Do not attempt to grant background access if foreground access is not either already
418             // granted or requested
419             if (group.isBackgroundGroup()) {
420                 // Check if a foreground permission is already granted
421                 boolean foregroundGroupAlreadyGranted = mAppPermissions.getPermissionGroup(
422                         group.getName()).areRuntimePermissionsGranted();
423                 boolean hasForegroundRequest = (getForegroundGroupState(group.getName()) != null);
424 
425                 if (!foregroundGroupAlreadyGranted && !hasForegroundRequest) {
426                     // The background permission cannot be granted at this time
427                     int numPermissions = groupState.affectedPermissions.length;
428                     for (int permissionNum = 0; permissionNum < numPermissions; permissionNum++) {
429                         Log.w(LOG_TAG,
430                                 "Cannot grant " + groupState.affectedPermissions[permissionNum]
431                                         + " as the matching foreground permission is not already "
432                                         + "granted.");
433                     }
434 
435                     groupState.mState = GroupState.STATE_SKIPPED;
436 
437                     reportRequestResult(groupState.affectedPermissions,
438                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
439                 }
440             }
441         }
442 
443         setContentView(mViewHandler.createView());
444 
445         Window window = getWindow();
446         WindowManager.LayoutParams layoutParams = window.getAttributes();
447         mViewHandler.updateWindowAttributes(layoutParams);
448         window.setAttributes(layoutParams);
449 
450         // Restore UI state after lifecycle events. This has to be before
451         // showNextPermissionGroupGrantRequest is called. showNextPermissionGroupGrantRequest might
452         // update the UI and the UI behaves differently for updates and initial creations.
453         if (icicle != null) {
454             mViewHandler.loadInstanceState(icicle);
455         }
456 
457         if (!showNextPermissionGroupGrantRequest()) {
458             setResultAndFinish();
459         }
460     }
461 
462     /**
463      * Update the {@link #mRequestedPermissions} if the system reports them as granted.
464      *
465      * <p>This also updates the {@link #mAppPermissions} state and switches to the next group grant
466      * request if the current group becomes granted.
467      */
updateIfPermissionsWereGranted()468     private void updateIfPermissionsWereGranted() {
469         PackageManager pm = getPackageManager();
470 
471         boolean mightShowNextGroup = true;
472         int numGroupStates = mRequestGrantPermissionGroups.size();
473         for (int i = 0; i < numGroupStates; i++) {
474             GroupState groupState = mRequestGrantPermissionGroups.valueAt(i);
475 
476             if (groupState == null || groupState.mState != GroupState.STATE_UNKNOWN) {
477                 // Group has already been approved / denied via the UI by the user
478                 continue;
479             }
480 
481             boolean allAffectedPermissionsOfThisGroupAreGranted = true;
482 
483             if (groupState.affectedPermissions == null) {
484                 // It is not clear which permissions belong to this group, hence never skip this
485                 // view
486                 allAffectedPermissionsOfThisGroupAreGranted = false;
487             } else {
488                 for (int permNum = 0; permNum < groupState.affectedPermissions.length;
489                         permNum++) {
490                     if (pm.checkPermission(groupState.affectedPermissions[permNum], mCallingPackage)
491                             == PERMISSION_DENIED) {
492                         allAffectedPermissionsOfThisGroupAreGranted = false;
493                         break;
494                     }
495                 }
496             }
497 
498             if (allAffectedPermissionsOfThisGroupAreGranted) {
499                 groupState.mState = GroupState.STATE_ALLOWED;
500 
501                 if (mightShowNextGroup) {
502                     // The UI currently displays the first group with
503                     // mState == STATE_UNKNOWN. So we are switching to next group until we
504                     // could not allow a group that was still unknown
505                     if (!showNextPermissionGroupGrantRequest()) {
506                         setResultAndFinish();
507                     }
508                 }
509             } else {
510                 mightShowNextGroup = false;
511             }
512         }
513     }
514 
515     @Override
onStart()516     protected void onStart() {
517         super.onStart();
518 
519         try {
520             mPermissionChangeListener = new PermissionChangeListener();
521         } catch (NameNotFoundException e) {
522             setResultAndFinish();
523             return;
524         }
525         PackageManager pm = getPackageManager();
526         pm.addOnPermissionsChangeListener(mPermissionChangeListener);
527 
528         // get notified when the package is removed
529         mPackageRemovalMonitor = new PackageRemovalMonitor(this, mCallingPackage) {
530             @Override
531             public void onPackageRemoved() {
532                 Log.w(LOG_TAG, mCallingPackage + " was uninstalled");
533 
534                 finish();
535             }
536         };
537         mPackageRemovalMonitor.register();
538 
539         // check if the package was removed while this activity was not started
540         try {
541             pm.getPackageInfo(mCallingPackage, 0);
542         } catch (NameNotFoundException e) {
543             Log.w(LOG_TAG, mCallingPackage + " was uninstalled while this activity was stopped", e);
544             finish();
545         }
546 
547         updateIfPermissionsWereGranted();
548     }
549 
550     @Override
onResume()551     protected void onResume() {
552         if (!showNextPermissionGroupGrantRequest()) {
553             setResultAndFinish();
554         }
555         super.onResume();
556     }
557 
558     @Override
onStop()559     protected void onStop() {
560         super.onStop();
561 
562         if (mPackageRemovalMonitor != null) {
563             mPackageRemovalMonitor.unregister();
564             mPackageRemovalMonitor = null;
565         }
566 
567         if (mPermissionChangeListener != null) {
568             getPackageManager().removeOnPermissionsChangeListener(mPermissionChangeListener);
569             mPermissionChangeListener = null;
570         }
571     }
572 
573     @Override
dispatchTouchEvent(MotionEvent ev)574     public boolean dispatchTouchEvent(MotionEvent ev) {
575         View rootView = getWindow().getDecorView();
576         if (rootView.getTop() != 0) {
577             // We are animating the top view, need to compensate for that in motion events.
578             ev.setLocation(ev.getX(), ev.getY() - rootView.getTop());
579         }
580         return super.dispatchTouchEvent(ev);
581     }
582 
583     /**
584      * Compose a key that stores the GroupState.mState in the instance state.
585      *
586      * @param requestGrantPermissionGroupsKey The key of the permission group
587      *
588      * @return A unique key to be used in the instance state
589      */
getInstanceStateKey( Pair<String, Boolean> requestGrantPermissionGroupsKey)590     private static String getInstanceStateKey(
591             Pair<String, Boolean> requestGrantPermissionGroupsKey) {
592         return GrantPermissionsActivity.class.getName() + "_"
593                 + requestGrantPermissionGroupsKey.first + "_"
594                 + requestGrantPermissionGroupsKey.second;
595     }
596 
597     @Override
onSaveInstanceState(Bundle outState)598     protected void onSaveInstanceState(Bundle outState) {
599         super.onSaveInstanceState(outState);
600 
601         mViewHandler.saveInstanceState(outState);
602 
603         outState.putLong(KEY_REQUEST_ID, mRequestId);
604 
605         int numGroups = mRequestGrantPermissionGroups.size();
606         for (int i = 0; i < numGroups; i++) {
607             int state = mRequestGrantPermissionGroups.valueAt(i).mState;
608 
609             if (state != GroupState.STATE_UNKNOWN) {
610                 outState.putInt(getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(i)), state);
611             }
612         }
613     }
614 
615     /**
616      * @return the background group state for the permission group with the {@code name}
617      */
getBackgroundGroupState(String name)618     private GroupState getBackgroundGroupState(String name) {
619         return mRequestGrantPermissionGroups.get(new Pair<>(name, true));
620     }
621 
622     /**
623      * @return the foreground group state for the permission group with the {@code name}
624      */
getForegroundGroupState(String name)625     private GroupState getForegroundGroupState(String name) {
626         return mRequestGrantPermissionGroups.get(new Pair<>(name, false));
627     }
628 
shouldShowRequestForGroupState(GroupState groupState)629     private boolean shouldShowRequestForGroupState(GroupState groupState) {
630         if (groupState.mState == GroupState.STATE_SKIPPED) {
631             return false;
632         }
633 
634         GroupState foregroundGroup = getForegroundGroupState(groupState.mGroup.getName());
635         if (groupState.mGroup.isBackgroundGroup()
636                 && (foregroundGroup != null && shouldShowRequestForGroupState(foregroundGroup))) {
637             // If an app requests both foreground and background permissions of the same group,
638             // we only show one request
639             return false;
640         }
641 
642         return !mPermissionGroupsToSkip.contains(groupState.mGroup.getName());
643     }
644 
showNextPermissionGroupGrantRequest()645     private boolean showNextPermissionGroupGrantRequest() {
646         int numGroupStates = mRequestGrantPermissionGroups.size();
647         int numGrantRequests = 0;
648         for (int i = 0; i < numGroupStates; i++) {
649             if (shouldShowRequestForGroupState(mRequestGrantPermissionGroups.valueAt(i))) {
650                 numGrantRequests++;
651             }
652         }
653 
654         int currentIndex = 0;
655         List<GroupState> groupStates = new ArrayList<>(mRequestGrantPermissionGroups.values());
656         Collections.sort(groupStates, (s1, s2) -> -Boolean.compare(s1.mGroup.supportsOneTimeGrant(),
657                 s2.mGroup.supportsOneTimeGrant()));
658         for (GroupState groupState : groupStates) {
659             if (!shouldShowRequestForGroupState(groupState)) {
660                 continue;
661             }
662 
663             if (groupState.mState == GroupState.STATE_UNKNOWN) {
664                 GroupState foregroundGroupState;
665                 GroupState backgroundGroupState;
666                 if (groupState.mGroup.isBackgroundGroup()) {
667                     backgroundGroupState = groupState;
668                     foregroundGroupState = getForegroundGroupState(groupState.mGroup.getName());
669                 } else {
670                     foregroundGroupState = groupState;
671                     backgroundGroupState = getBackgroundGroupState(groupState.mGroup.getName());
672                 }
673 
674                 CharSequence appLabel = mAppPermissions.getAppLabel();
675 
676                 Icon icon;
677                 try {
678                     icon = Icon.createWithResource(groupState.mGroup.getIconPkg(),
679                             groupState.mGroup.getIconResId());
680                 } catch (Resources.NotFoundException e) {
681                     Log.e(LOG_TAG, "Cannot load icon for group" + groupState.mGroup.getName(), e);
682                     icon = null;
683                 }
684 
685                 // If no background permissions are granted yet, we need to ask for background
686                 // permissions
687                 boolean needBackgroundPermission = false;
688                 boolean isBackgroundPermissionUserSet = false;
689                 if (backgroundGroupState != null) {
690                     if (!backgroundGroupState.mGroup.areRuntimePermissionsGranted()) {
691                         needBackgroundPermission = true;
692                         isBackgroundPermissionUserSet = backgroundGroupState.mGroup.isUserSet();
693                     }
694                 }
695 
696                 // If no foreground permissions are granted yet, we need to ask for foreground
697                 // permissions
698                 boolean needForegroundPermission = false;
699                 boolean isForegroundPermissionUserSet = false;
700                 if (foregroundGroupState != null) {
701                     if (!foregroundGroupState.mGroup.areRuntimePermissionsGranted()) {
702                         needForegroundPermission = true;
703                         isForegroundPermissionUserSet = foregroundGroupState.mGroup.isUserSet();
704                     }
705                 }
706 
707                 mButtonVisibilities = new boolean[NEXT_BUTTON];
708                 mButtonVisibilities[ALLOW_BUTTON] = true;
709                 mButtonVisibilities[DENY_BUTTON] = true;
710                 mButtonVisibilities[ALLOW_ONE_TIME_BUTTON] =
711                         groupState.mGroup.supportsOneTimeGrant();
712 
713                 int messageId;
714                 int detailMessageId = 0;
715 
716                 if (mAppPermissions.getPackageInfo().applicationInfo.targetSdkVersion
717                         >= Build.VERSION_CODES.R) {
718                     if (groupState.mGroup.hasPermissionWithBackgroundMode()
719                             || groupState.mGroup.isBackgroundGroup()) {
720                         if (needForegroundPermission && needBackgroundPermission) {
721                             if (mCouldHaveFgCapabilities) {
722                                 sendToSettings(groupState);
723                                 return true;
724                             }
725                             // Shouldn't be reached as background must be requested as a singleton
726                             return false;
727                         } else if (needForegroundPermission) {
728                             // Case: sdk >= R, BG/FG permission requesting FG only
729                             messageId = groupState.mGroup.getRequest();
730                             if (mCouldHaveFgCapabilities) {
731                                 sendToSettings(groupState);
732                                 return true;
733                             }
734                             mButtonVisibilities[ALLOW_BUTTON] = false;
735                             mButtonVisibilities[ALLOW_FOREGROUND_BUTTON] = true;
736                             mButtonVisibilities[DENY_BUTTON] =
737                                     !isForegroundPermissionUserSet;
738                             mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
739                                     isForegroundPermissionUserSet;
740                         } else if (needBackgroundPermission) {
741                             // Case: sdk >= R, BG/FG permission requesting BG only
742                             sendToSettings(groupState);
743                             return true;
744                         } else {
745                             // Not reached as the permissions should be auto-granted
746                             return false;
747                         }
748                     } else {
749                         // Case: sdk >= R, Requesting normal permission
750                         messageId = groupState.mGroup.getRequest();
751                         mButtonVisibilities[DENY_BUTTON] =
752                                 !isForegroundPermissionUserSet;
753                         mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
754                                 isForegroundPermissionUserSet;
755                         if (groupState.mGroup.getName().equals(Manifest.permission_group.CAMERA)
756                                 || groupState.mGroup.getName().equals(
757                                 Manifest.permission_group.MICROPHONE)) {
758                             mButtonVisibilities[ALLOW_BUTTON] = false;
759                             if (mCouldHaveFgCapabilities
760                                     || Utils.isEmergencyApp(this, mCallingPackage)) {
761                                 mButtonVisibilities[ALLOW_ALWAYS_BUTTON] = true;
762                                 mButtonVisibilities[ALLOW_ONE_TIME_BUTTON] = false;
763                             } else {
764                                 mButtonVisibilities[ALLOW_FOREGROUND_BUTTON] = true;
765                             }
766                         }
767                     }
768                 } else {
769                     if (groupState.mGroup.hasPermissionWithBackgroundMode()
770                             || groupState.mGroup.isBackgroundGroup()) {
771                         if (mCouldHaveFgCapabilities) {
772                             // Only allow granting of background location
773                             messageId = groupState.mGroup.getBackgroundRequest();
774                             detailMessageId = groupState.mGroup.getBackgroundRequestDetail();
775                             mButtonVisibilities[ALLOW_BUTTON] = false;
776                             mButtonVisibilities[ALLOW_ONE_TIME_BUTTON] = false;
777                             mButtonVisibilities[DENY_BUTTON] =
778                                     !isForegroundPermissionUserSet;
779                             mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
780                                     isForegroundPermissionUserSet;
781                         } else {
782                             if (needForegroundPermission && needBackgroundPermission) {
783                                 // Case: sdk < R, BG/FG permission requesting both
784                                 messageId = groupState.mGroup.getBackgroundRequest();
785                                 detailMessageId = groupState.mGroup.getBackgroundRequestDetail();
786                                 mButtonVisibilities[ALLOW_BUTTON] = false;
787                                 mButtonVisibilities[ALLOW_FOREGROUND_BUTTON] = true;
788                                 mButtonVisibilities[DENY_BUTTON] =
789                                         !isForegroundPermissionUserSet;
790                                 mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
791                                         isForegroundPermissionUserSet;
792                             } else if (needForegroundPermission) {
793                                 // Case: sdk < R, BG/FG permission requesting FG only
794                                 messageId = groupState.mGroup.getRequest();
795                                 mButtonVisibilities[ALLOW_BUTTON] = false;
796                                 mButtonVisibilities[ALLOW_FOREGROUND_BUTTON] = true;
797                                 mButtonVisibilities[DENY_BUTTON] =
798                                         !isForegroundPermissionUserSet;
799                                 mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
800                                         isForegroundPermissionUserSet;
801                             } else if (needBackgroundPermission) {
802                                 // Case: sdk < R, BG/FG permission requesting BG only
803                                 messageId = groupState.mGroup.getUpgradeRequest();
804                                 detailMessageId = groupState.mGroup.getUpgradeRequestDetail();
805                                 mButtonVisibilities[ALLOW_BUTTON] = false;
806                                 mButtonVisibilities[DENY_BUTTON] = false;
807                                 mButtonVisibilities[ALLOW_ONE_TIME_BUTTON] = false;
808                                 if (mAppPermissions.getPermissionGroup(
809                                         groupState.mGroup.getName()).isOneTime()) {
810                                     mButtonVisibilities[NO_UPGRADE_OT_BUTTON] =
811                                             !isBackgroundPermissionUserSet;
812                                     mButtonVisibilities[NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON] =
813                                             isBackgroundPermissionUserSet;
814                                 } else {
815                                     mButtonVisibilities[NO_UPGRADE_BUTTON] =
816                                             !isBackgroundPermissionUserSet;
817                                     mButtonVisibilities[NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON] =
818                                             isBackgroundPermissionUserSet;
819                                 }
820                             } else {
821                                 // Not reached as the permissions should be auto-granted
822                                 return false;
823                             }
824                         }
825                     } else {
826                         // Case: sdk < R, Requesting normal permission
827                         messageId = groupState.mGroup.getRequest();
828                         mButtonVisibilities[DENY_BUTTON] =
829                                 !isForegroundPermissionUserSet;
830                         mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
831                                 isForegroundPermissionUserSet;
832                         if (groupState.mGroup.getName().equals(Manifest.permission_group.CAMERA)
833                                 || groupState.mGroup.getName().equals(
834                                         Manifest.permission_group.MICROPHONE)) {
835                             mButtonVisibilities[ALLOW_BUTTON] = false;
836                             if (mCouldHaveFgCapabilities
837                                     || Utils.isEmergencyApp(this, mCallingPackage)) {
838                                 mButtonVisibilities[ALLOW_ALWAYS_BUTTON] = true;
839                                 mButtonVisibilities[ALLOW_ONE_TIME_BUTTON] = false;
840                             } else {
841                                 mButtonVisibilities[ALLOW_FOREGROUND_BUTTON] = true;
842                             }
843                         }
844                     }
845                 }
846 
847                 CharSequence message = getRequestMessage(appLabel, groupState.mGroup, this,
848                         messageId);
849 
850                 Spanned detailMessage = null;
851                 if (detailMessageId != 0) {
852                     detailMessage =
853                             new SpannableString(getText(detailMessageId));
854                     Annotation[] annotations = detailMessage.getSpans(
855                             0, detailMessage.length(), Annotation.class);
856                     int numAnnotations = annotations.length;
857                     for (int i = 0; i < numAnnotations; i++) {
858                         Annotation annotation = annotations[i];
859                         if (annotation.getValue().equals(ANNOTATION_ID)) {
860                             int start = detailMessage.getSpanStart(annotation);
861                             int end = detailMessage.getSpanEnd(annotation);
862                             ClickableSpan clickableSpan = getLinkToAppPermissions(groupState);
863                             SpannableString spannableString =
864                                     new SpannableString(detailMessage);
865                             spannableString.setSpan(clickableSpan, start, end, 0);
866                             detailMessage = spannableString;
867                             mButtonVisibilities[LINK_TO_SETTINGS] = true;
868                             break;
869                         }
870                     }
871                 }
872 
873                 // Set the permission message as the title so it can be announced.
874                 setTitle(message);
875 
876                 mViewHandler.updateUi(groupState.mGroup.getName(), numGrantRequests, currentIndex,
877                         icon, message, detailMessage, mButtonVisibilities);
878 
879                 return true;
880             }
881 
882             if (groupState.mState != GroupState.STATE_SKIPPED) {
883                 currentIndex++;
884             }
885         }
886 
887         return false;
888     }
889 
sendToSettings(GroupState groupState)890     private void sendToSettings(GroupState groupState) {
891         if (mActivityResultCallback == null) {
892             startAppPermissionFragment(groupState);
893             mActivityResultCallback = data -> {
894                 if (data == null || data.getStringExtra(
895                         EXTRA_RESULT_PERMISSION_INTERACTED) == null) {
896                     // User didn't interact, count against rate limit
897                     if (groupState.mGroup.isUserSet()) {
898                         groupState.mGroup.setUserFixed(true);
899                     } else {
900                         groupState.mGroup.setUserSet(true);
901                     }
902                 }
903                 mPermissionGroupsToSkip.add(groupState.mGroup.getName());
904             };
905         }
906     }
907 
getLinkToAppPermissions(GroupState groupState)908     private ClickableSpan getLinkToAppPermissions(GroupState groupState) {
909         return new ClickableSpan() {
910             @Override
911             public void onClick(View widget) {
912                 logGrantPermissionActivityButtons(groupState.mGroup.getName(), LINKED_TO_SETTINGS);
913                 startAppPermissionFragment(groupState);
914                 mActivityResultCallback = data -> {
915                     if (data != null) {
916                         String groupName = data.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED);
917                         if (groupName != null) {
918                             mPermissionGroupsToSkip.add(groupName);
919                             int result = data.getIntExtra(EXTRA_RESULT_PERMISSION_RESULT, -1);
920                             logSettingsInteraction(groupName, result);
921                         }
922                     }
923                 };
924             }
925         };
926     }
927 
928     private void logSettingsInteraction(String groupName, int result) {
929         GroupState foregroundGroupState = getForegroundGroupState(groupName);
930         GroupState backgroundGroupState = getBackgroundGroupState(groupName);
931         switch (result) {
932             case GRANTED_ALWAYS:
933                 if (foregroundGroupState != null) {
934                     reportRequestResult(foregroundGroupState.affectedPermissions,
935                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS);
936                 }
937                 if (backgroundGroupState != null) {
938                     reportRequestResult(backgroundGroupState.affectedPermissions,
939                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS);
940                 }
941                 break;
942             case GRANTED_FOREGROUND_ONLY:
943                 if (foregroundGroupState != null) {
944                     reportRequestResult(foregroundGroupState.affectedPermissions,
945                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS);
946                 }
947                 if (backgroundGroupState != null) {
948                     reportRequestResult(backgroundGroupState.affectedPermissions,
949                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS);
950                 }
951                 break;
952             case DENIED:
953                 if (foregroundGroupState != null) {
954                     reportRequestResult(foregroundGroupState.affectedPermissions,
955                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS);
956                 }
957                 if (backgroundGroupState != null) {
958                     reportRequestResult(backgroundGroupState.affectedPermissions,
959                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS);
960                 }
961                 break;
962             case DENIED_DO_NOT_ASK_AGAIN:
963                 if (foregroundGroupState != null) {
964                     reportRequestResult(foregroundGroupState.affectedPermissions,
965                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE_IN_SETTINGS);
966                 }
967                 if (backgroundGroupState != null) {
968                     reportRequestResult(backgroundGroupState.affectedPermissions,
969                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE_IN_SETTINGS);
970                 }
971                 break;
972         }
973     }
974 
975     private void startAppPermissionFragment(GroupState groupState) {
976         Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION)
977                 .putExtra(Intent.EXTRA_PACKAGE_NAME, mAppPermissions.getPackageInfo().packageName)
978                 .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupState.mGroup.getName())
979                 .putExtra(Intent.EXTRA_USER, groupState.mGroup.getUser())
980                 .putExtra(EXTRA_CALLER_NAME, GrantPermissionsActivity.class.getName())
981                 .putExtra(Constants.EXTRA_SESSION_ID, mRequestId)
982                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
983         startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE);
984     }
985 
986     @Override
987     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
988         if (requestCode == APP_PERMISSION_REQUEST_CODE && mActivityResultCallback != null) {
989             mActivityResultCallback.accept(data);
990             mActivityResultCallback = null;
991         }
992     }
993 
994     @Override
995     public void onPermissionGrantResult(String name,
996             @GrantPermissionsViewHandler.Result int result) {
997         GroupState foregroundGroupState = getForegroundGroupState(name);
998         GroupState backgroundGroupState = getBackgroundGroupState(name);
999 
1000         if (result == GRANTED_ALWAYS || result == GRANTED_FOREGROUND_ONLY
1001                 || result == DENIED_DO_NOT_ASK_AGAIN) {
1002             KeyguardManager kgm = getSystemService(KeyguardManager.class);
1003 
1004             if (kgm.isDeviceLocked()) {
1005                 kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() {
1006                             @Override
1007                             public void onDismissError() {
1008                                 Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " result="
1009                                         + result);
1010                             }
1011 
1012                             @Override
1013                             public void onDismissCancelled() {
1014                                 // do nothing (i.e. stay at the current permission group)
1015                             }
1016 
1017                             @Override
1018                             public void onDismissSucceeded() {
1019                                 // Now the keyguard is dismissed, hence the device is not locked
1020                                 // anymore
1021                                 onPermissionGrantResult(name, result);
1022                             }
1023                         });
1024 
1025                 return;
1026             }
1027         }
1028 
1029         logGrantPermissionActivityButtons(name, result);
1030         switch (result) {
1031             case CANCELED:
1032                 if (foregroundGroupState != null) {
1033                     reportRequestResult(foregroundGroupState.affectedPermissions,
1034                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED);
1035                 }
1036                 if (backgroundGroupState != null) {
1037                     reportRequestResult(backgroundGroupState.affectedPermissions,
1038                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED);
1039                 }
1040                 setResultAndFinish();
1041                 return;
1042             case GRANTED_ALWAYS :
1043                 if (foregroundGroupState != null) {
1044                     onPermissionGrantResultSingleState(foregroundGroupState, true, false, false);
1045                 }
1046                 if (backgroundGroupState != null) {
1047                     onPermissionGrantResultSingleState(backgroundGroupState, true, false, false);
1048                 }
1049                 break;
1050             case GRANTED_FOREGROUND_ONLY :
1051                 if (foregroundGroupState != null) {
1052                     onPermissionGrantResultSingleState(foregroundGroupState, true, false, false);
1053                 }
1054                 if (backgroundGroupState != null) {
1055                     onPermissionGrantResultSingleState(backgroundGroupState, false, false, false);
1056                 }
1057                 break;
1058             case GRANTED_ONE_TIME:
1059                 if (foregroundGroupState != null) {
1060                     onPermissionGrantResultSingleState(foregroundGroupState, true, true, false);
1061                 }
1062                 if (backgroundGroupState != null) {
1063                     onPermissionGrantResultSingleState(backgroundGroupState, false, true, false);
1064                 }
1065                 break;
1066             case DENIED :
1067                 if (foregroundGroupState != null) {
1068                     onPermissionGrantResultSingleState(foregroundGroupState, false, false, false);
1069                 }
1070                 if (backgroundGroupState != null) {
1071                     onPermissionGrantResultSingleState(backgroundGroupState, false, false, false);
1072                 }
1073                 break;
1074             case DENIED_DO_NOT_ASK_AGAIN :
1075                 if (foregroundGroupState != null) {
1076                     onPermissionGrantResultSingleState(foregroundGroupState, false, false, true);
1077                 }
1078                 if (backgroundGroupState != null) {
1079                     onPermissionGrantResultSingleState(backgroundGroupState, false, false, true);
1080                 }
1081                 break;
1082         }
1083 
1084         if (!showNextPermissionGroupGrantRequest()) {
1085             setResultAndFinish();
1086         }
1087     }
1088 
1089     /**
1090      * Grants or revoked the affected permissions for a single {@link GroupState}.
1091      *
1092      * @param groupState The group state with the permissions to grant/revoke
1093      * @param granted {@code true} if the permissions should be granted, {@code false} if they
1094      *        should be revoked
1095      * @param isOneTime if the permission is temporary and should be revoked automatically
1096      * @param doNotAskAgain if the permissions should be revoked should be app be allowed to ask
1097      *        again for the same permissions?
1098      */
1099     private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted,
1100             boolean isOneTime, boolean doNotAskAgain) {
1101         if (groupState != null && groupState.mGroup != null
1102                 && groupState.mState == GroupState.STATE_UNKNOWN) {
1103             if (granted) {
1104                 int permissionGrantRequestResult =
1105                         PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED;
1106 
1107                 if (isOneTime) {
1108                     groupState.mGroup.setOneTime(true);
1109                     permissionGrantRequestResult =
1110                             PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_ONE_TIME;
1111                 } else {
1112                     groupState.mGroup.setOneTime(false);
1113                 }
1114 
1115                 groupState.mGroup.grantRuntimePermissions(true, doNotAskAgain,
1116                         groupState.affectedPermissions);
1117                 groupState.mState = GroupState.STATE_ALLOWED;
1118 
1119                 reportRequestResult(groupState.affectedPermissions, permissionGrantRequestResult);
1120             } else {
1121                 groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
1122                         groupState.affectedPermissions);
1123                 groupState.mGroup.setOneTime(false);
1124                 groupState.mState = GroupState.STATE_DENIED;
1125 
1126                 reportRequestResult(groupState.affectedPermissions, doNotAskAgain
1127                         ?
1128                         PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
1129                         : PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED);
1130             }
1131         }
1132     }
1133 
1134     @Override
1135     public void onBackPressed() {
1136         mViewHandler.onBackPressed();
1137     }
1138 
1139     @Override
1140     public void finish() {
1141         setResultIfNeeded(RESULT_CANCELED);
1142         if (mAutoGrantPermissionsNotifier != null) {
1143             mAutoGrantPermissionsNotifier.notifyOfAutoGrantPermissions(true);
1144         }
1145         super.finish();
1146     }
1147 
1148     private PackageInfo getCallingPackageInfo() {
1149         try {
1150             return getPackageManager().getPackageInfo(mCallingPackage,
1151                     PackageManager.GET_PERMISSIONS);
1152         } catch (NameNotFoundException e) {
1153             Log.i(LOG_TAG, "No package: " + mCallingPackage, e);
1154             return null;
1155         }
1156     }
1157 
1158     private void setResultIfNeeded(int resultCode) {
1159         if (!mResultSet) {
1160             mResultSet = true;
1161             logRequestedPermissionGroups();
1162             Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS);
1163             result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions);
1164 
1165             PackageManager pm = getPackageManager();
1166             int numRequestedPermissions = mRequestedPermissions.length;
1167             int[] grantResults = new int[numRequestedPermissions];
1168             for (int i = 0; i < numRequestedPermissions; i++) {
1169                 grantResults[i] = pm.checkPermission(mRequestedPermissions[i], mCallingPackage);
1170             }
1171 
1172             result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, grantResults);
1173             setResult(resultCode, result);
1174         }
1175     }
1176 
1177     private void setResultAndFinish() {
1178         setResultIfNeeded(RESULT_OK);
1179         finish();
1180     }
1181 
1182     private void logRequestedPermissionGroups() {
1183         if (mRequestGrantPermissionGroups.isEmpty()) {
1184             return;
1185         }
1186 
1187         final int groupCount = mRequestGrantPermissionGroups.size();
1188         List<AppPermissionGroup> groups = new ArrayList<>(groupCount);
1189         for (GroupState groupState : mRequestGrantPermissionGroups.values()) {
1190             groups.add(groupState.mGroup);
1191         }
1192 
1193         SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups);
1194     }
1195 
1196     /**
1197      * Get the actually requested permissions when a permission is requested.
1198      *
1199      * <p>>In some cases requesting to grant a single permission requires the system to grant
1200      * additional permissions. E.g. before N-MR1 a single permission of a group caused the whole
1201      * group to be granted. Another case are permissions that are split into two. For apps that
1202      * target an SDK before the split, this method automatically adds the split off permission.
1203      *
1204      * @param permission The requested permission
1205      *
1206      * @return The actually requested permissions
1207      */
1208     private ArrayList<String> computeAffectedPermissions(String permission) {
1209         int requestingAppTargetSDK =
1210                 mAppPermissions.getPackageInfo().applicationInfo.targetSdkVersion;
1211 
1212         // If a permission is split, all permissions the original permission is split into are
1213         // affected
1214         ArrayList<String> extendedBySplitPerms = new ArrayList<>();
1215         extendedBySplitPerms.add(permission);
1216 
1217         List<PermissionManager.SplitPermissionInfo> splitPerms = getSystemService(
1218                 PermissionManager.class).getSplitPermissions();
1219         int numSplitPerms = splitPerms.size();
1220         for (int i = 0; i < numSplitPerms; i++) {
1221             PermissionManager.SplitPermissionInfo splitPerm = splitPerms.get(i);
1222 
1223             if (requestingAppTargetSDK < splitPerm.getTargetSdk()
1224                     && permission.equals(splitPerm.getSplitPermission())) {
1225                 extendedBySplitPerms.addAll(splitPerm.getNewPermissions());
1226             }
1227         }
1228 
1229         // For <= N_MR1 apps all permissions of the groups of the requested permissions are affected
1230         if (requestingAppTargetSDK <= Build.VERSION_CODES.N_MR1) {
1231             ArrayList<String> extendedBySplitPermsAndGroup = new ArrayList<>();
1232 
1233             int numExtendedBySplitPerms = extendedBySplitPerms.size();
1234             for (int splitPermNum = 0; splitPermNum < numExtendedBySplitPerms; splitPermNum++) {
1235                 AppPermissionGroup group = mAppPermissions.getGroupForPermission(
1236                         extendedBySplitPerms.get(splitPermNum));
1237 
1238                 if (group == null) {
1239                     continue;
1240                 }
1241 
1242                 ArrayList<Permission> permissionsInGroup = group.getPermissions();
1243                 int numPermissionsInGroup = permissionsInGroup.size();
1244                 for (int permNum = 0; permNum < numPermissionsInGroup; permNum++) {
1245                     extendedBySplitPermsAndGroup.add(permissionsInGroup.get(permNum).getName());
1246                 }
1247             }
1248 
1249             return extendedBySplitPermsAndGroup;
1250         } else {
1251             return extendedBySplitPerms;
1252         }
1253     }
1254 
1255     private void logGrantPermissionActivityButtons(String permissionGroupName, int grantResult) {
1256         int clickedButton = 0;
1257         int presentedButtons = getButtonState();
1258         switch (grantResult) {
1259             case GRANTED_ALWAYS:
1260                 if (mButtonVisibilities[ALLOW_BUTTON]) {
1261                     clickedButton = 1 << ALLOW_BUTTON;
1262                 } else {
1263                     clickedButton = 1 << ALLOW_ALWAYS_BUTTON;
1264                 }
1265                 break;
1266             case GRANTED_FOREGROUND_ONLY:
1267                 clickedButton = 1 << ALLOW_FOREGROUND_BUTTON;
1268                 break;
1269             case DENIED:
1270                 if (mButtonVisibilities[NO_UPGRADE_BUTTON]) {
1271                     clickedButton = 1 << NO_UPGRADE_BUTTON;
1272                 } else if (mButtonVisibilities[NO_UPGRADE_OT_BUTTON]) {
1273                     clickedButton = 1 << NO_UPGRADE_OT_BUTTON;
1274                 } else if (mButtonVisibilities[DENY_BUTTON]) {
1275                     clickedButton = 1 << DENY_BUTTON;
1276                 }
1277                 break;
1278             case DENIED_DO_NOT_ASK_AGAIN:
1279                 if (mButtonVisibilities[NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON]) {
1280                     clickedButton = 1 << NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON;
1281                 } else if (mButtonVisibilities[NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON]) {
1282                     clickedButton = 1 << NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON;
1283                 } else if (mButtonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON]) {
1284                     clickedButton = 1 << DENY_AND_DONT_ASK_AGAIN_BUTTON;
1285                 }
1286                 break;
1287             case GRANTED_ONE_TIME:
1288                 clickedButton = 1 << ALLOW_ONE_TIME_BUTTON;
1289                 break;
1290             case LINKED_TO_SETTINGS:
1291                 clickedButton = 1 << LINK_TO_SETTINGS;
1292             case CANCELED:
1293                 // fall through
1294             default:
1295                 break;
1296         }
1297 
1298         PermissionControllerStatsLog.write(GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS,
1299                 permissionGroupName, mCallingUid, mCallingPackage, presentedButtons,
1300                 clickedButton, mRequestId);
1301         Log.v(LOG_TAG, "Logged buttons presented and clicked permissionGroupName="
1302                 + permissionGroupName + " uid=" + mCallingUid + " package=" + mCallingPackage
1303                 + " presentedButtons=" + presentedButtons + " clickedButton=" + clickedButton
1304                 + " sessionId=" + mRequestId);
1305     }
1306 
1307     private int getButtonState() {
1308         if (mButtonVisibilities == null) {
1309             return 0;
1310         }
1311         int buttonState = 0;
1312         for (int i = NEXT_BUTTON - 1; i >= 0; i--) {
1313             buttonState *= 2;
1314             if (mButtonVisibilities[i]) {
1315                 buttonState++;
1316             }
1317         }
1318         return buttonState;
1319     }
1320 
1321     private static final class GroupState {
1322         static final int STATE_UNKNOWN = 0;
1323         static final int STATE_ALLOWED = 1;
1324         static final int STATE_DENIED = 2;
1325         static final int STATE_SKIPPED = 3;
1326 
1327         final AppPermissionGroup mGroup;
1328         int mState = STATE_UNKNOWN;
1329 
1330         /** Permissions of this group that need to be granted, null == no permissions of group */
1331         String[] affectedPermissions;
1332 
1333         GroupState(AppPermissionGroup group) {
1334             mGroup = group;
1335         }
1336     }
1337 
1338     private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener {
1339         final int mCallingPackageUid;
1340 
1341         PermissionChangeListener() throws NameNotFoundException {
1342             mCallingPackageUid = getPackageManager().getPackageUid(mCallingPackage, 0);
1343         }
1344 
1345         @Override
1346         public void onPermissionsChanged(int uid) {
1347             if (uid == mCallingPackageUid) {
1348                 updateIfPermissionsWereGranted();
1349             }
1350         }
1351     }
1352 
1353     /**
1354      * Creates the AutoGrantPermissionsNotifier lazily in case there's no policy set
1355      * device-wide (common case).
1356      *
1357      * @return An initalized {@code AutoGrantPermissionsNotifier} instance.
1358      */
1359     private @NonNull AutoGrantPermissionsNotifier getAutoGrantNotifier() {
1360         if (mAutoGrantPermissionsNotifier == null) {
1361             mAutoGrantPermissionsNotifier = new AutoGrantPermissionsNotifier(
1362                     this, mCallingPackageInfo);
1363         }
1364 
1365         return mAutoGrantPermissionsNotifier;
1366     }
1367 }
1368