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.packageinstaller.permission.ui; 18 19 import static android.content.pm.PackageManager.PERMISSION_DENIED; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 22 import android.app.admin.DevicePolicyManager; 23 import android.app.KeyguardManager; 24 import android.content.Intent; 25 import android.content.pm.PackageInfo; 26 import android.content.pm.PackageManager; 27 import android.content.pm.PackageManager.NameNotFoundException; 28 import android.content.pm.PackageParser; 29 import android.content.pm.PermissionInfo; 30 import android.content.res.Configuration; 31 import android.content.res.Resources; 32 import android.graphics.drawable.Icon; 33 import android.os.Build; 34 import android.os.Bundle; 35 import android.text.Html; 36 import android.text.Spanned; 37 import android.util.ArraySet; 38 import android.util.Log; 39 import android.view.KeyEvent; 40 import android.view.MotionEvent; 41 import android.view.View; 42 import android.view.Window; 43 import android.view.WindowManager; 44 45 import com.android.internal.content.PackageMonitor; 46 import com.android.internal.logging.nano.MetricsProto; 47 import com.android.packageinstaller.DeviceUtils; 48 import com.android.packageinstaller.R; 49 import com.android.packageinstaller.permission.model.AppPermissionGroup; 50 import com.android.packageinstaller.permission.model.AppPermissions; 51 import com.android.packageinstaller.permission.model.Permission; 52 import com.android.packageinstaller.permission.ui.auto.GrantPermissionsAutoViewHandler; 53 import com.android.packageinstaller.permission.ui.handheld.GrantPermissionsViewHandlerImpl; 54 import com.android.packageinstaller.permission.utils.ArrayUtils; 55 import com.android.packageinstaller.permission.utils.EventLogger; 56 import com.android.packageinstaller.permission.utils.SafetyNetLogger; 57 58 import java.util.ArrayList; 59 import java.util.Arrays; 60 import java.util.LinkedHashMap; 61 import java.util.List; 62 63 public class GrantPermissionsActivity extends OverlayTouchActivity 64 implements GrantPermissionsViewHandler.ResultListener { 65 66 private static final String LOG_TAG = "GrantPermissionsActivity"; 67 68 private String[] mRequestedPermissions; 69 private int[] mGrantResults; 70 71 private LinkedHashMap<String, GroupState> mRequestGrantPermissionGroups = new LinkedHashMap<>(); 72 73 private GrantPermissionsViewHandler mViewHandler; 74 private AppPermissions mAppPermissions; 75 76 boolean mResultSet; 77 78 private PackageManager.OnPermissionsChangedListener mPermissionChangeListener; 79 private PackageMonitor mPackageMonitor; 80 81 private String mCallingPackage; 82 getPermissionPolicy()83 private int getPermissionPolicy() { 84 DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class); 85 return devicePolicyManager.getPermissionPolicy(null); 86 } 87 88 @Override onCreate(Bundle icicle)89 public void onCreate(Bundle icicle) { 90 super.onCreate(icicle); 91 92 // Cache this as this can only read on onCreate, not later. 93 mCallingPackage = getCallingPackage(); 94 95 mPackageMonitor = new PackageMonitor() { 96 @Override 97 public void onPackageRemoved(String packageName, int uid) { 98 if (mCallingPackage.equals(packageName)) { 99 Log.w(LOG_TAG, mCallingPackage + " was uninstalled"); 100 101 finish(); 102 } 103 } 104 }; 105 106 setFinishOnTouchOutside(false); 107 108 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); 109 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); 110 111 setTitle(R.string.permission_request_title); 112 113 if (DeviceUtils.isTelevision(this)) { 114 mViewHandler = new com.android.packageinstaller.permission.ui.television 115 .GrantPermissionsViewHandlerImpl(this, 116 mCallingPackage).setResultListener(this); 117 } else if (DeviceUtils.isWear(this)) { 118 mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this); 119 } else if (DeviceUtils.isAuto(this)) { 120 mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage) 121 .setResultListener(this); 122 } else { 123 mViewHandler = new com.android.packageinstaller.permission.ui.handheld 124 .GrantPermissionsViewHandlerImpl(this, mCallingPackage) 125 .setResultListener(this); 126 } 127 128 mRequestedPermissions = getIntent().getStringArrayExtra( 129 PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); 130 if (mRequestedPermissions == null) { 131 mRequestedPermissions = new String[0]; 132 } 133 134 final int requestedPermCount = mRequestedPermissions.length; 135 mGrantResults = new int[requestedPermCount]; 136 Arrays.fill(mGrantResults, PackageManager.PERMISSION_DENIED); 137 138 if (requestedPermCount == 0) { 139 setResultAndFinish(); 140 return; 141 } 142 143 try { 144 mPermissionChangeListener = new PermissionChangeListener(); 145 } catch (NameNotFoundException e) { 146 setResultAndFinish(); 147 return; 148 } 149 150 PackageInfo callingPackageInfo = getCallingPackageInfo(); 151 152 if (callingPackageInfo == null || callingPackageInfo.requestedPermissions == null 153 || callingPackageInfo.requestedPermissions.length <= 0) { 154 setResultAndFinish(); 155 return; 156 } 157 158 // Don't allow legacy apps to request runtime permissions. 159 if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { 160 // Returning empty arrays means a cancellation. 161 mRequestedPermissions = new String[0]; 162 mGrantResults = new int[0]; 163 setResultAndFinish(); 164 return; 165 } 166 167 updateAlreadyGrantedPermissions(callingPackageInfo, getPermissionPolicy()); 168 169 mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false, 170 new Runnable() { 171 @Override 172 public void run() { 173 setResultAndFinish(); 174 } 175 }); 176 177 for (String requestedPermission : mRequestedPermissions) { 178 AppPermissionGroup group = null; 179 for (AppPermissionGroup nextGroup : mAppPermissions.getPermissionGroups()) { 180 if (nextGroup.hasPermission(requestedPermission)) { 181 group = nextGroup; 182 break; 183 } 184 } 185 if (group == null) { 186 continue; 187 } 188 if (!group.isGrantingAllowed()) { 189 // Skip showing groups that we know cannot be granted. 190 continue; 191 } 192 // We allow the user to choose only non-fixed permissions. A permission 193 // is fixed either by device policy or the user denying with prejudice. 194 if (!group.isUserFixed() && !group.isPolicyFixed()) { 195 switch (getPermissionPolicy()) { 196 case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { 197 if (!group.areRuntimePermissionsGranted()) { 198 group.grantRuntimePermissions(false, computeAffectedPermissions( 199 callingPackageInfo, requestedPermission)); 200 } 201 group.setPolicyFixed(); 202 } break; 203 204 case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { 205 if (group.areRuntimePermissionsGranted()) { 206 group.revokeRuntimePermissions(false, computeAffectedPermissions( 207 callingPackageInfo, requestedPermission)); 208 } 209 group.setPolicyFixed(); 210 } break; 211 212 default: { 213 if (!group.areRuntimePermissionsGranted()) { 214 GroupState state = mRequestGrantPermissionGroups.get(group.getName()); 215 if (state == null) { 216 state = new GroupState(group); 217 mRequestGrantPermissionGroups.put(group.getName(), state); 218 } 219 String[] affectedPermissions = computeAffectedPermissions( 220 callingPackageInfo, requestedPermission); 221 if (affectedPermissions != null) { 222 for (String affectedPermission : affectedPermissions) { 223 state.affectedPermissions = ArrayUtils.appendString( 224 state.affectedPermissions, affectedPermission); 225 } 226 } 227 } else { 228 group.grantRuntimePermissions(false, computeAffectedPermissions( 229 callingPackageInfo, requestedPermission)); 230 updateGrantResults(group); 231 } 232 } break; 233 } 234 } else { 235 // if the permission is fixed, ensure that we return the right request result 236 updateGrantResults(group); 237 } 238 } 239 240 setContentView(mViewHandler.createView()); 241 242 Window window = getWindow(); 243 WindowManager.LayoutParams layoutParams = window.getAttributes(); 244 mViewHandler.updateWindowAttributes(layoutParams); 245 window.setAttributes(layoutParams); 246 247 if (!showNextPermissionGroupGrantRequest()) { 248 setResultAndFinish(); 249 } else if (icicle == null) { 250 int numRequestedPermissions = mRequestedPermissions.length; 251 for (int permissionNum = 0; permissionNum < numRequestedPermissions; permissionNum++) { 252 String permission = mRequestedPermissions[permissionNum]; 253 254 EventLogger.logPermission( 255 MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUESTED, permission, 256 mAppPermissions.getPackageInfo().packageName); 257 } 258 } 259 } 260 261 262 /** 263 * Update the {@link #mRequestedPermissions} if the system reports them as granted. 264 * 265 * <p>This also updates the {@link #mAppPermissions} state and switches to the next group grant 266 * request if the current group becomes granted. 267 */ updateIfPermissionsWereGranted()268 private void updateIfPermissionsWereGranted() { 269 updateAlreadyGrantedPermissions(getCallingPackageInfo(), getPermissionPolicy()); 270 271 ArraySet<String> grantedPermissionNames = new ArraySet<>(mRequestedPermissions.length); 272 for (int i = 0; i < mRequestedPermissions.length; i++) { 273 if (mGrantResults[i] == PERMISSION_GRANTED) { 274 grantedPermissionNames.add(mRequestedPermissions[i]); 275 } 276 } 277 278 boolean mightShowNextGroup = true; 279 int numGroups = mAppPermissions.getPermissionGroups().size(); 280 for (int groupNum = 0; groupNum < numGroups; groupNum++) { 281 AppPermissionGroup group = mAppPermissions.getPermissionGroups().get(groupNum); 282 GroupState groupState = mRequestGrantPermissionGroups.get(group.getName()); 283 284 if (groupState == null || groupState.mState != GroupState.STATE_UNKNOWN) { 285 // Group has already been approved / denied via the UI by the user 286 continue; 287 } 288 289 boolean allAffectedPermissionsOfThisGroupAreGranted = true; 290 291 if (groupState.affectedPermissions == null) { 292 // It is not clear which permissions belong to this group, hence never skip this 293 // view 294 allAffectedPermissionsOfThisGroupAreGranted = false; 295 } else { 296 for (int permNum = 0; permNum < groupState.affectedPermissions.length; 297 permNum++) { 298 if (!grantedPermissionNames.contains( 299 groupState.affectedPermissions[permNum])) { 300 allAffectedPermissionsOfThisGroupAreGranted = false; 301 break; 302 } 303 } 304 } 305 306 if (allAffectedPermissionsOfThisGroupAreGranted) { 307 groupState.mState = GroupState.STATE_ALLOWED; 308 309 if (mightShowNextGroup) { 310 // The UI currently displays the first group with 311 // mState == STATE_UNKNOWN. So we are switching to next group until we 312 // could not allow a group that was still unknown 313 if (!showNextPermissionGroupGrantRequest()) { 314 setResultAndFinish(); 315 } 316 } 317 } else { 318 mightShowNextGroup = false; 319 } 320 } 321 } 322 323 @Override onStart()324 protected void onStart() { 325 super.onStart(); 326 327 PackageManager pm = getPackageManager(); 328 pm.addOnPermissionsChangeListener(mPermissionChangeListener); 329 330 // get notified when the package is removed 331 mPackageMonitor.register(this, getMainLooper(), false); 332 333 // check if the package was removed while this activity was not started 334 try { 335 pm.getPackageInfo(mCallingPackage, 0); 336 } catch (NameNotFoundException e) { 337 Log.w(LOG_TAG, mCallingPackage + " was uninstalled while this activity was stopped", e); 338 finish(); 339 } 340 341 updateIfPermissionsWereGranted(); 342 } 343 344 @Override onStop()345 protected void onStop() { 346 super.onStop(); 347 348 mPackageMonitor.unregister(); 349 350 getPackageManager().removeOnPermissionsChangeListener(mPermissionChangeListener); 351 } 352 353 @Override onConfigurationChanged(Configuration newConfig)354 public void onConfigurationChanged(Configuration newConfig) { 355 super.onConfigurationChanged(newConfig); 356 // We need to relayout the window as dialog width may be 357 // different in landscape vs portrait which affect the min 358 // window height needed to show all content. We have to 359 // re-add the window to force it to be resized if needed. 360 View decor = getWindow().getDecorView(); 361 if (decor.getParent() != null) { 362 getWindowManager().removeViewImmediate(decor); 363 getWindowManager().addView(decor, decor.getLayoutParams()); 364 if (mViewHandler instanceof GrantPermissionsViewHandlerImpl) { 365 ((GrantPermissionsViewHandlerImpl) mViewHandler).onConfigurationChanged(); 366 } 367 } 368 } 369 370 @Override dispatchTouchEvent(MotionEvent ev)371 public boolean dispatchTouchEvent(MotionEvent ev) { 372 View rootView = getWindow().getDecorView(); 373 if (rootView.getTop() != 0) { 374 // We are animating the top view, need to compensate for that in motion events. 375 ev.setLocation(ev.getX(), ev.getY() - rootView.getTop()); 376 } 377 return super.dispatchTouchEvent(ev); 378 } 379 380 @Override onSaveInstanceState(Bundle outState)381 protected void onSaveInstanceState(Bundle outState) { 382 super.onSaveInstanceState(outState); 383 mViewHandler.saveInstanceState(outState); 384 } 385 386 @Override onRestoreInstanceState(Bundle savedInstanceState)387 protected void onRestoreInstanceState(Bundle savedInstanceState) { 388 super.onRestoreInstanceState(savedInstanceState); 389 mViewHandler.loadInstanceState(savedInstanceState); 390 } 391 showNextPermissionGroupGrantRequest()392 private boolean showNextPermissionGroupGrantRequest() { 393 final int groupCount = mRequestGrantPermissionGroups.size(); 394 395 int currentIndex = 0; 396 for (GroupState groupState : mRequestGrantPermissionGroups.values()) { 397 if (groupState.mState == GroupState.STATE_UNKNOWN) { 398 CharSequence appLabel = mAppPermissions.getAppLabel(); 399 400 Spanned message = null; 401 int requestMessageId = groupState.mGroup.getRequest(); 402 if (requestMessageId != 0) { 403 try { 404 message = Html.fromHtml(getPackageManager().getResourcesForApplication( 405 groupState.mGroup.getDeclaringPackage()).getString(requestMessageId, 406 appLabel), 0); 407 } catch (NameNotFoundException ignored) { 408 } 409 } 410 411 if (message == null) { 412 message = Html.fromHtml(getString(R.string.permission_warning_template, 413 appLabel, groupState.mGroup.getDescription()), 0); 414 } 415 416 // Set the permission message as the title so it can be announced. 417 setTitle(message); 418 419 // Set the new grant view 420 // TODO: Use a real message for the action. We need group action APIs 421 Resources resources; 422 try { 423 resources = getPackageManager().getResourcesForApplication( 424 groupState.mGroup.getIconPkg()); 425 } catch (NameNotFoundException e) { 426 // Fallback to system. 427 resources = Resources.getSystem(); 428 } 429 430 Icon icon; 431 try { 432 icon = Icon.createWithResource(resources, groupState.mGroup.getIconResId()); 433 } catch (Resources.NotFoundException e) { 434 Log.e(LOG_TAG, "Cannot load icon for group" + groupState.mGroup.getName(), e); 435 icon = null; 436 } 437 438 mViewHandler.updateUi(groupState.mGroup.getName(), groupCount, currentIndex, 439 icon, message, groupState.mGroup.isUserSet()); 440 return true; 441 } 442 443 currentIndex++; 444 } 445 446 return false; 447 } 448 449 @Override onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain)450 public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) { 451 KeyguardManager kgm = getSystemService(KeyguardManager.class); 452 453 if (kgm.isDeviceLocked()) { 454 kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() { 455 @Override 456 public void onDismissError() { 457 Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " granted=" 458 + granted + " doNotAskAgain=" + doNotAskAgain); 459 } 460 461 @Override 462 public void onDismissCancelled() { 463 // do nothing (i.e. stay at the current permission group) 464 } 465 466 @Override 467 public void onDismissSucceeded() { 468 // Now the keyguard is dismissed, hence the device is not locked 469 // anymore 470 onPermissionGrantResult(name, granted, doNotAskAgain); 471 } 472 }); 473 474 return; 475 } 476 477 GroupState groupState = mRequestGrantPermissionGroups.get(name); 478 if (groupState != null && groupState.mGroup != null) { 479 if (granted) { 480 groupState.mGroup.grantRuntimePermissions(doNotAskAgain, 481 groupState.affectedPermissions); 482 groupState.mState = GroupState.STATE_ALLOWED; 483 } else { 484 groupState.mGroup.revokeRuntimePermissions(doNotAskAgain, 485 groupState.affectedPermissions); 486 groupState.mState = GroupState.STATE_DENIED; 487 488 int numRequestedPermissions = mRequestedPermissions.length; 489 for (int i = 0; i < numRequestedPermissions; i++) { 490 String permission = mRequestedPermissions[i]; 491 492 if (groupState.mGroup.hasPermission(permission)) { 493 EventLogger.logPermission( 494 MetricsProto.MetricsEvent.ACTION_PERMISSION_DENIED, permission, 495 mAppPermissions.getPackageInfo().packageName); 496 } 497 } 498 } 499 updateGrantResults(groupState.mGroup); 500 } 501 if (!showNextPermissionGroupGrantRequest()) { 502 setResultAndFinish(); 503 } 504 } 505 updateGrantResults(AppPermissionGroup group)506 private void updateGrantResults(AppPermissionGroup group) { 507 for (Permission permission : group.getPermissions()) { 508 final int index = ArrayUtils.indexOf( 509 mRequestedPermissions, permission.getName()); 510 if (index >= 0) { 511 mGrantResults[index] = permission.isGranted() ? PackageManager.PERMISSION_GRANTED 512 : PackageManager.PERMISSION_DENIED; 513 } 514 } 515 } 516 517 @Override onKeyDown(int keyCode, KeyEvent event)518 public boolean onKeyDown(int keyCode, KeyEvent event) { 519 // We do not allow backing out. 520 return keyCode == KeyEvent.KEYCODE_BACK; 521 } 522 523 @Override onKeyUp(int keyCode, KeyEvent event)524 public boolean onKeyUp(int keyCode, KeyEvent event) { 525 // We do not allow backing out. 526 return keyCode == KeyEvent.KEYCODE_BACK; 527 } 528 529 @Override finish()530 public void finish() { 531 setResultIfNeeded(RESULT_CANCELED); 532 super.finish(); 533 } 534 computePermissionGrantState(PackageInfo callingPackageInfo, String permission, int permissionPolicy)535 private int computePermissionGrantState(PackageInfo callingPackageInfo, 536 String permission, int permissionPolicy) { 537 boolean permissionRequested = false; 538 539 for (int i = 0; i < callingPackageInfo.requestedPermissions.length; i++) { 540 if (permission.equals(callingPackageInfo.requestedPermissions[i])) { 541 permissionRequested = true; 542 if ((callingPackageInfo.requestedPermissionsFlags[i] 543 & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) { 544 return PERMISSION_GRANTED; 545 } 546 break; 547 } 548 } 549 550 if (!permissionRequested) { 551 return PERMISSION_DENIED; 552 } 553 554 try { 555 PermissionInfo pInfo = getPackageManager().getPermissionInfo(permission, 0); 556 if ((pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) 557 != PermissionInfo.PROTECTION_DANGEROUS) { 558 return PERMISSION_DENIED; 559 } 560 if ((pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 561 && callingPackageInfo.applicationInfo.isInstantApp()) { 562 return PERMISSION_DENIED; 563 } 564 if ((pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0 565 && callingPackageInfo.applicationInfo.targetSdkVersion 566 < Build.VERSION_CODES.M) { 567 return PERMISSION_DENIED; 568 } 569 } catch (NameNotFoundException e) { 570 return PERMISSION_DENIED; 571 } 572 573 switch (permissionPolicy) { 574 case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { 575 return PERMISSION_GRANTED; 576 } 577 default: { 578 return PERMISSION_DENIED; 579 } 580 } 581 } 582 getCallingPackageInfo()583 private PackageInfo getCallingPackageInfo() { 584 try { 585 return getPackageManager().getPackageInfo(mCallingPackage, 586 PackageManager.GET_PERMISSIONS); 587 } catch (NameNotFoundException e) { 588 Log.i(LOG_TAG, "No package: " + mCallingPackage, e); 589 return null; 590 } 591 } 592 updateAlreadyGrantedPermissions(PackageInfo callingPackageInfo, int permissionPolicy)593 private void updateAlreadyGrantedPermissions(PackageInfo callingPackageInfo, 594 int permissionPolicy) { 595 final int requestedPermCount = mRequestedPermissions.length; 596 for (int i = 0; i < requestedPermCount; i++) { 597 String permission = mRequestedPermissions[i]; 598 599 if (permission != null) { 600 if (computePermissionGrantState(callingPackageInfo, permission, permissionPolicy) 601 == PERMISSION_GRANTED) { 602 mGrantResults[i] = PERMISSION_GRANTED; 603 } 604 } 605 } 606 } 607 setResultIfNeeded(int resultCode)608 private void setResultIfNeeded(int resultCode) { 609 if (!mResultSet) { 610 mResultSet = true; 611 logRequestedPermissionGroups(); 612 Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS); 613 result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions); 614 result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, mGrantResults); 615 setResult(resultCode, result); 616 } 617 } 618 setResultAndFinish()619 private void setResultAndFinish() { 620 setResultIfNeeded(RESULT_OK); 621 finish(); 622 } 623 logRequestedPermissionGroups()624 private void logRequestedPermissionGroups() { 625 if (mRequestGrantPermissionGroups.isEmpty()) { 626 return; 627 } 628 629 final int groupCount = mRequestGrantPermissionGroups.size(); 630 List<AppPermissionGroup> groups = new ArrayList<>(groupCount); 631 for (GroupState groupState : mRequestGrantPermissionGroups.values()) { 632 groups.add(groupState.mGroup); 633 } 634 635 SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups); 636 } 637 computeAffectedPermissions(PackageInfo callingPkg, String permission)638 private static String[] computeAffectedPermissions(PackageInfo callingPkg, 639 String permission) { 640 // For <= N_MR1 apps all permissions are affected. 641 if (callingPkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) { 642 return null; 643 } 644 645 // For N_MR1+ apps only the requested permission is affected with addition 646 // to splits of this permission applicable to apps targeting N_MR1. 647 String[] permissions = new String[] {permission}; 648 for (PackageParser.SplitPermissionInfo splitPerm : PackageParser.SPLIT_PERMISSIONS) { 649 if (splitPerm.targetSdk <= Build.VERSION_CODES.N_MR1 650 || callingPkg.applicationInfo.targetSdkVersion >= splitPerm.targetSdk 651 || !permission.equals(splitPerm.rootPerm)) { 652 continue; 653 } 654 for (int i = 0; i < splitPerm.newPerms.length; i++) { 655 final String newPerm = splitPerm.newPerms[i]; 656 permissions = ArrayUtils.appendString(permissions, newPerm); 657 } 658 } 659 660 return permissions; 661 } 662 663 private static final class GroupState { 664 static final int STATE_UNKNOWN = 0; 665 static final int STATE_ALLOWED = 1; 666 static final int STATE_DENIED = 2; 667 668 final AppPermissionGroup mGroup; 669 int mState = STATE_UNKNOWN; 670 671 /** Permissions of this group that need to be granted, null == all permissions of group */ 672 String[] affectedPermissions; 673 GroupState(AppPermissionGroup group)674 GroupState(AppPermissionGroup group) { 675 mGroup = group; 676 } 677 } 678 679 private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener { 680 final int mCallingPackageUid; 681 PermissionChangeListener()682 PermissionChangeListener() throws NameNotFoundException { 683 mCallingPackageUid = getPackageManager().getPackageUid(mCallingPackage, 0); 684 } 685 686 @Override onPermissionsChanged(int uid)687 public void onPermissionsChanged(int uid) { 688 if (uid == mCallingPackageUid) { 689 updateIfPermissionsWereGranted(); 690 } 691 } 692 } 693 } 694