1 /* 2 * Copyright (C) 2010 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.settings.applications.specialaccess.deviceadmin; 18 19 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; 20 21 import android.app.Activity; 22 import android.app.ActivityManager; 23 import android.app.AppOpsManager; 24 import android.app.Dialog; 25 import android.app.admin.DeviceAdminInfo; 26 import android.app.admin.DeviceAdminReceiver; 27 import android.app.admin.DevicePolicyManager; 28 import android.app.settings.SettingsEnums; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.DialogInterface; 32 import android.content.Intent; 33 import android.content.pm.ActivityInfo; 34 import android.content.pm.ApplicationInfo; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.PackageManager; 37 import android.content.pm.PackageManager.NameNotFoundException; 38 import android.content.pm.ResolveInfo; 39 import android.content.pm.UserInfo; 40 import android.content.res.Resources; 41 import android.graphics.drawable.Drawable; 42 import android.os.Binder; 43 import android.os.Bundle; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.RemoteCallback; 47 import android.os.RemoteException; 48 import android.os.UserHandle; 49 import android.os.UserManager; 50 import android.text.TextUtils; 51 import android.text.TextUtils.TruncateAt; 52 import android.util.EventLog; 53 import android.util.Log; 54 import android.view.Display; 55 import android.view.LayoutInflater; 56 import android.view.View; 57 import android.view.ViewGroup; 58 import android.view.ViewTreeObserver; 59 import android.view.WindowManager; 60 import android.widget.Button; 61 import android.widget.ImageView; 62 import android.widget.TextView; 63 64 import androidx.appcompat.app.AlertDialog; 65 66 import com.android.settings.EventLogTags; 67 import com.android.settings.R; 68 import com.android.settings.fuelgauge.BatteryUtils; 69 import com.android.settings.overlay.FeatureFactory; 70 import com.android.settings.users.UserDialogs; 71 import com.android.settingslib.RestrictedLockUtils; 72 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 73 import com.android.settingslib.RestrictedLockUtilsInternal; 74 import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; 75 76 import org.xmlpull.v1.XmlPullParserException; 77 78 import java.io.IOException; 79 import java.util.ArrayList; 80 import java.util.List; 81 import java.util.Optional; 82 83 /** 84 * A confirmation screen for enabling administractor. 85 */ 86 public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { 87 static final String TAG = "DeviceAdminAdd"; 88 89 static final int DIALOG_WARNING = 1; 90 91 private static final int MAX_ADD_MSG_LINES_PORTRAIT = 5; 92 private static final int MAX_ADD_MSG_LINES_LANDSCAPE = 2; 93 private static final int MAX_ADD_MSG_LINES = 15; 94 95 /** 96 * Optional key to map to the package name of the Device Admin. 97 * Currently only used when uninstalling an active device admin. 98 */ 99 public static final String EXTRA_DEVICE_ADMIN_PACKAGE_NAME = 100 "android.app.extra.DEVICE_ADMIN_PACKAGE_NAME"; 101 102 public static final String EXTRA_CALLED_FROM_SUPPORT_DIALOG = 103 "android.app.extra.CALLED_FROM_SUPPORT_DIALOG"; 104 105 private final IBinder mToken = new Binder(); 106 Handler mHandler; 107 108 DevicePolicyManager mDPM; 109 AppOpsManager mAppOps; 110 DeviceAdminInfo mDeviceAdmin; 111 String mAddMsgText; 112 String mProfileOwnerName; 113 114 ImageView mAdminIcon; 115 TextView mAdminName; 116 TextView mAdminDescription; 117 TextView mAddMsg; 118 TextView mProfileOwnerWarning; 119 ImageView mAddMsgExpander; 120 boolean mAddMsgEllipsized = true; 121 TextView mAdminWarning; 122 TextView mSupportMessage; 123 ViewGroup mAdminPolicies; 124 Button mActionButton; 125 Button mUninstallButton; 126 Button mCancelButton; 127 128 boolean mUninstalling = false; 129 boolean mAdding; 130 boolean mRefreshing; 131 boolean mWaitingForRemoveMsg; 132 boolean mAddingProfileOwner; 133 boolean mAdminPoliciesInitialized; 134 135 boolean mIsCalledFromSupportDialog = false; 136 137 private LayoutInflater mLayoutInflaternflater; 138 139 @Override onCreate(Bundle icicle)140 protected void onCreate(Bundle icicle) { 141 super.onCreate(icicle); 142 143 mHandler = new Handler(getMainLooper()); 144 145 mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); 146 mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); 147 mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 148 PackageManager packageManager = getPackageManager(); 149 150 if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { 151 Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); 152 finish(); 153 return; 154 } 155 156 mIsCalledFromSupportDialog = getIntent().getBooleanExtra( 157 EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); 158 159 String action = getIntent().getAction(); 160 ComponentName who = (ComponentName)getIntent().getParcelableExtra( 161 DevicePolicyManager.EXTRA_DEVICE_ADMIN); 162 if (who == null) { 163 String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); 164 Optional<ComponentName> installedAdmin = findAdminWithPackageName(packageName); 165 if (!installedAdmin.isPresent()) { 166 Log.w(TAG, "No component specified in " + action); 167 finish(); 168 return; 169 } 170 who = installedAdmin.get(); 171 mUninstalling = true; 172 } 173 174 if (action != null && action.equals(DevicePolicyManager.ACTION_SET_PROFILE_OWNER)) { 175 setResult(RESULT_CANCELED); 176 setFinishOnTouchOutside(true); 177 mAddingProfileOwner = true; 178 mProfileOwnerName = 179 getIntent().getStringExtra(DevicePolicyManager.EXTRA_PROFILE_OWNER_NAME); 180 String callingPackage = getCallingPackage(); 181 if (callingPackage == null || !callingPackage.equals(who.getPackageName())) { 182 Log.e(TAG, "Unknown or incorrect caller"); 183 finish(); 184 return; 185 } 186 try { 187 PackageInfo packageInfo = packageManager.getPackageInfo(callingPackage, 0); 188 if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 189 Log.e(TAG, "Cannot set a non-system app as a profile owner"); 190 finish(); 191 return; 192 } 193 } catch (NameNotFoundException nnfe) { 194 Log.e(TAG, "Cannot find the package " + callingPackage); 195 finish(); 196 return; 197 } 198 } 199 200 ActivityInfo ai; 201 try { 202 ai = packageManager.getReceiverInfo(who, PackageManager.GET_META_DATA); 203 } catch (PackageManager.NameNotFoundException e) { 204 Log.w(TAG, "Unable to retrieve device policy " + who, e); 205 finish(); 206 return; 207 } 208 209 // When activating, make sure the given component name is actually a valid device admin. 210 // No need to check this when deactivating, because it is safe to deactivate an active 211 // invalid device admin. 212 if (!mDPM.isAdminActive(who)) { 213 List<ResolveInfo> avail = packageManager.queryBroadcastReceivers( 214 new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), 215 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); 216 int count = avail == null ? 0 : avail.size(); 217 boolean found = false; 218 for (int i=0; i<count; i++) { 219 ResolveInfo ri = avail.get(i); 220 if (ai.packageName.equals(ri.activityInfo.packageName) 221 && ai.name.equals(ri.activityInfo.name)) { 222 try { 223 // We didn't retrieve the meta data for all possible matches, so 224 // need to use the activity info of this specific one that was retrieved. 225 ri.activityInfo = ai; 226 DeviceAdminInfo dpi = new DeviceAdminInfo(this, ri); 227 found = true; 228 } catch (XmlPullParserException e) { 229 Log.w(TAG, "Bad " + ri.activityInfo, e); 230 } catch (IOException e) { 231 Log.w(TAG, "Bad " + ri.activityInfo, e); 232 } 233 break; 234 } 235 } 236 if (!found) { 237 Log.w(TAG, "Request to add invalid device admin: " + who); 238 finish(); 239 return; 240 } 241 } 242 243 ResolveInfo ri = new ResolveInfo(); 244 ri.activityInfo = ai; 245 try { 246 mDeviceAdmin = new DeviceAdminInfo(this, ri); 247 } catch (XmlPullParserException e) { 248 Log.w(TAG, "Unable to retrieve device policy " + who, e); 249 finish(); 250 return; 251 } catch (IOException e) { 252 Log.w(TAG, "Unable to retrieve device policy " + who, e); 253 finish(); 254 return; 255 } 256 257 // This admin already exists, an we have two options at this point. If new policy 258 // bits are set, show the user the new list. If nothing has changed, simply return 259 // "OK" immediately. 260 if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) { 261 mRefreshing = false; 262 if (mDPM.isAdminActive(who)) { 263 if (mDPM.isRemovingAdmin(who, android.os.Process.myUserHandle().getIdentifier())) { 264 Log.w(TAG, "Requested admin is already being removed: " + who); 265 finish(); 266 return; 267 } 268 269 ArrayList<DeviceAdminInfo.PolicyInfo> newPolicies = mDeviceAdmin.getUsedPolicies(); 270 for (int i = 0; i < newPolicies.size(); i++) { 271 DeviceAdminInfo.PolicyInfo pi = newPolicies.get(i); 272 if (!mDPM.hasGrantedPolicy(who, pi.ident)) { 273 mRefreshing = true; 274 break; 275 } 276 } 277 if (!mRefreshing) { 278 // Nothing changed (or policies were removed) - return immediately 279 setResult(Activity.RESULT_OK); 280 finish(); 281 return; 282 } 283 } 284 } 285 286 final CharSequence addMsgCharSequence = getIntent().getCharSequenceExtra( 287 DevicePolicyManager.EXTRA_ADD_EXPLANATION); 288 if (addMsgCharSequence != null) { 289 mAddMsgText = addMsgCharSequence.toString(); 290 } 291 292 if (mAddingProfileOwner) { 293 // If we're trying to add a profile owner and user setup hasn't completed yet, no 294 // need to prompt for permission. Just add and finish 295 if (!mDPM.hasUserSetupCompleted()) { 296 addAndFinish(); 297 return; 298 } 299 300 // othewise, only the defined default supervision profile owner can be set after user 301 // setup. 302 final String supervisor = getString( 303 com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent); 304 if (TextUtils.isEmpty(supervisor)) { 305 Log.w(TAG, "Unable to set profile owner post-setup, no default supervisor" 306 + "profile owner defined"); 307 finish(); 308 return; 309 } 310 311 final ComponentName supervisorComponent = ComponentName.unflattenFromString( 312 supervisor); 313 if (supervisorComponent == null || who.compareTo(supervisorComponent) != 0) { 314 Log.w(TAG, "Unable to set non-default profile owner post-setup " + who); 315 finish(); 316 return; 317 } 318 319 // Build and show the simplified dialog 320 final Dialog dialog = new AlertDialog.Builder(this) 321 .setTitle(getText(R.string.profile_owner_add_title_simplified)) 322 .setView(R.layout.profile_owner_add) 323 .setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() { 324 public void onClick(DialogInterface dialog, int which) { 325 addAndFinish(); 326 } 327 }) 328 .setNegativeButton(R.string.cancel, null) 329 .setOnDismissListener(new DialogInterface.OnDismissListener() { 330 public void onDismiss(DialogInterface dialogInterface) { 331 finish(); 332 } 333 }) 334 .create(); 335 dialog.show(); 336 337 mActionButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE); 338 mActionButton.setFilterTouchesWhenObscured(true); 339 mAddMsg = dialog.findViewById(R.id.add_msg_simplified); 340 mAddMsg.setText(mAddMsgText); 341 mAdminWarning = dialog.findViewById(R.id.admin_warning_simplified); 342 mAdminWarning.setText(getString(R.string.device_admin_warning_simplified, 343 mProfileOwnerName)); 344 return; 345 } 346 setContentView(R.layout.device_admin_add); 347 348 mAdminIcon = (ImageView)findViewById(R.id.admin_icon); 349 mAdminName = (TextView)findViewById(R.id.admin_name); 350 mAdminDescription = (TextView)findViewById(R.id.admin_description); 351 mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning); 352 353 mAddMsg = (TextView)findViewById(R.id.add_msg); 354 mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander); 355 final View.OnClickListener onClickListener = new View.OnClickListener() { 356 @Override 357 public void onClick(View v) { 358 toggleMessageEllipsis(mAddMsg); 359 } 360 }; 361 mAddMsgExpander.setOnClickListener(onClickListener); 362 363 // Determine whether the message can be collapsed - getLineCount() gives the correct 364 // number of lines only after a layout pass. 365 mAddMsg.getViewTreeObserver().addOnGlobalLayoutListener( 366 new ViewTreeObserver.OnGlobalLayoutListener() { 367 @Override 368 public void onGlobalLayout() { 369 final int maxLines = getEllipsizedLines(); 370 // hide the icon if number of visible lines does not exceed maxLines 371 boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines; 372 mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE); 373 if (hideMsgExpander) { 374 ((View)mAddMsgExpander.getParent()).invalidate(); 375 } 376 mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this); 377 } 378 }); 379 380 // toggleMessageEllipsis also handles initial layout: 381 toggleMessageEllipsis(mAddMsg); 382 383 mAdminWarning = (TextView) findViewById(R.id.admin_warning); 384 mAdminPolicies = (ViewGroup) findViewById(R.id.admin_policies); 385 mSupportMessage = (TextView) findViewById(R.id.admin_support_message); 386 387 mCancelButton = (Button) findViewById(R.id.cancel_button); 388 mCancelButton.setFilterTouchesWhenObscured(true); 389 mCancelButton.setOnClickListener(new View.OnClickListener() { 390 public void onClick(View v) { 391 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER, 392 mDeviceAdmin.getActivityInfo().applicationInfo.uid); 393 finish(); 394 } 395 }); 396 397 mUninstallButton = (Button) findViewById(R.id.uninstall_button); 398 mUninstallButton.setFilterTouchesWhenObscured(true); 399 mUninstallButton.setOnClickListener(new View.OnClickListener() { 400 public void onClick(View v) { 401 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_UNINSTALLED_BY_USER, 402 mDeviceAdmin.getActivityInfo().applicationInfo.uid); 403 mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); 404 finish(); 405 } 406 }); 407 408 mActionButton = (Button) findViewById(R.id.action_button); 409 410 final View restrictedAction = findViewById(R.id.restricted_action); 411 restrictedAction.setFilterTouchesWhenObscured(true); 412 restrictedAction.setOnClickListener(new View.OnClickListener() { 413 public void onClick(View v) { 414 if (!mActionButton.isEnabled()) { 415 showPolicyTransparencyDialogIfRequired(); 416 return; 417 } 418 if (mAdding) { 419 addAndFinish(); 420 } else if (isManagedProfile(mDeviceAdmin) 421 && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { 422 final int userId = UserHandle.myUserId(); 423 UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, 424 new DialogInterface.OnClickListener() { 425 @Override 426 public void onClick(DialogInterface dialog, int which) { 427 UserManager um = UserManager.get(DeviceAdminAdd.this); 428 um.removeUser(userId); 429 finish(); 430 } 431 } 432 ).show(); 433 } else if (mUninstalling) { 434 mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); 435 finish(); 436 } else if (!mWaitingForRemoveMsg) { 437 try { 438 // Don't allow the admin to put a dialog up in front 439 // of us while we interact with the user. 440 ActivityManager.getService().stopAppSwitches(); 441 } catch (RemoteException e) { 442 } 443 mWaitingForRemoveMsg = true; 444 mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), 445 new RemoteCallback(new RemoteCallback.OnResultListener() { 446 @Override 447 public void onResult(Bundle result) { 448 CharSequence msg = result != null 449 ? result.getCharSequence( 450 DeviceAdminReceiver.EXTRA_DISABLE_WARNING) 451 : null; 452 continueRemoveAction(msg); 453 } 454 }, mHandler)); 455 // Don't want to wait too long. 456 getWindow().getDecorView().getHandler().postDelayed(new Runnable() { 457 @Override public void run() { 458 continueRemoveAction(null); 459 } 460 }, 2*1000); 461 } 462 } 463 }); 464 } 465 466 /** 467 * Shows a dialog to explain why the button is disabled if required. 468 */ showPolicyTransparencyDialogIfRequired()469 private void showPolicyTransparencyDialogIfRequired() { 470 if (isManagedProfile(mDeviceAdmin) 471 && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { 472 EnforcedAdmin enforcedAdmin; 473 ComponentName adminComponent = mDPM.getProfileOwnerAsUser(getUserId()); 474 if (adminComponent != null && mDPM.isOrganizationOwnedDeviceWithManagedProfile()) { 475 enforcedAdmin = new EnforcedAdmin(adminComponent, 476 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.of(getUserId())); 477 } else { 478 // Todo (b/151061366): Investigate this case to check if it is still viable. 479 if (hasBaseCantRemoveProfileRestriction()) { 480 // If DISALLOW_REMOVE_MANAGED_PROFILE is set by the system, there's no 481 // point showing a dialog saying it's disabled by an admin. 482 return; 483 } 484 enforcedAdmin = getAdminEnforcingCantRemoveProfile(); 485 } 486 if (enforcedAdmin != null) { 487 RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 488 DeviceAdminAdd.this, 489 enforcedAdmin); 490 } 491 } 492 } 493 addAndFinish()494 void addAndFinish() { 495 try { 496 logSpecialPermissionChange(true, mDeviceAdmin.getComponent().getPackageName()); 497 mDPM.setActiveAdmin(mDeviceAdmin.getComponent(), mRefreshing); 498 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_ACTIVATED_BY_USER, 499 mDeviceAdmin.getActivityInfo().applicationInfo.uid); 500 501 unrestrictAppIfPossible(BatteryUtils.getInstance(this)); 502 503 setResult(Activity.RESULT_OK); 504 } catch (RuntimeException e) { 505 // Something bad happened... could be that it was 506 // already set, though. 507 Log.w(TAG, "Exception trying to activate admin " 508 + mDeviceAdmin.getComponent(), e); 509 if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) { 510 setResult(Activity.RESULT_OK); 511 } 512 } 513 if (mAddingProfileOwner) { 514 try { 515 mDPM.setProfileOwner(mDeviceAdmin.getComponent(), 516 mProfileOwnerName, UserHandle.myUserId()); 517 } catch (RuntimeException re) { 518 setResult(Activity.RESULT_CANCELED); 519 } 520 } 521 finish(); 522 } 523 unrestrictAppIfPossible(BatteryUtils batteryUtils)524 void unrestrictAppIfPossible(BatteryUtils batteryUtils) { 525 // Unrestrict admin app if it is already been restricted 526 final String packageName = mDeviceAdmin.getComponent().getPackageName(); 527 batteryUtils.clearForceAppStandby(packageName); 528 } 529 continueRemoveAction(CharSequence msg)530 void continueRemoveAction(CharSequence msg) { 531 if (!mWaitingForRemoveMsg) { 532 return; 533 } 534 mWaitingForRemoveMsg = false; 535 if (msg == null) { 536 try { 537 ActivityManager.getService().resumeAppSwitches(); 538 } catch (RemoteException e) { 539 } 540 logSpecialPermissionChange(false, mDeviceAdmin.getComponent().getPackageName()); 541 mDPM.removeActiveAdmin(mDeviceAdmin.getComponent()); 542 finish(); 543 } else { 544 try { 545 // Continue preventing anything from coming in front. 546 ActivityManager.getService().stopAppSwitches(); 547 } catch (RemoteException e) { 548 } 549 Bundle args = new Bundle(); 550 args.putCharSequence( 551 DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg); 552 showDialog(DIALOG_WARNING, args); 553 } 554 } 555 logSpecialPermissionChange(boolean allow, String packageName)556 void logSpecialPermissionChange(boolean allow, String packageName) { 557 int logCategory = allow ? SettingsEnums.APP_SPECIAL_PERMISSION_ADMIN_ALLOW : 558 SettingsEnums.APP_SPECIAL_PERMISSION_ADMIN_DENY; 559 FeatureFactory.getFactory(this).getMetricsFeatureProvider().action( 560 SettingsEnums.PAGE_UNKNOWN, 561 logCategory, 562 SettingsEnums.PAGE_UNKNOWN, 563 packageName, 564 0); 565 } 566 567 @Override onResume()568 protected void onResume() { 569 super.onResume(); 570 mActionButton.setEnabled(true); 571 if (!mAddingProfileOwner) { 572 updateInterface(); 573 } 574 // As long as we are running, don't let anyone overlay stuff on top of the screen. 575 mAppOps.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, true, mToken); 576 mAppOps.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW, true, mToken); 577 578 } 579 580 @Override onPause()581 protected void onPause() { 582 super.onPause(); 583 // This just greys out the button. The actual listener is attached to R.id.restricted_action 584 mActionButton.setEnabled(false); 585 mAppOps.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, false, mToken); 586 mAppOps.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW, false, mToken); 587 try { 588 ActivityManager.getService().resumeAppSwitches(); 589 } catch (RemoteException e) { 590 } 591 } 592 593 @Override onUserLeaveHint()594 protected void onUserLeaveHint() { 595 super.onUserLeaveHint(); 596 // In case this is triggered from support dialog, finish this activity once the user leaves 597 // so that this won't appear as a background next time support dialog is triggered. This 598 // is because the support dialog activity and this belong to the same task and we can't 599 // start this in new activity since we need to know the calling package in this activity. 600 if (mIsCalledFromSupportDialog) { 601 finish(); 602 } 603 } 604 605 @Override onCreateDialog(int id, Bundle args)606 protected Dialog onCreateDialog(int id, Bundle args) { 607 switch (id) { 608 case DIALOG_WARNING: { 609 CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING); 610 AlertDialog.Builder builder = new AlertDialog.Builder(this); 611 builder.setMessage(msg); 612 builder.setPositiveButton(R.string.dlg_ok, 613 new DialogInterface.OnClickListener() { 614 public void onClick(DialogInterface dialog, int which) { 615 try { 616 ActivityManager.getService().resumeAppSwitches(); 617 } catch (RemoteException e) { 618 } 619 mDPM.removeActiveAdmin(mDeviceAdmin.getComponent()); 620 finish(); 621 } 622 }); 623 builder.setNegativeButton(R.string.dlg_cancel, null); 624 return builder.create(); 625 } 626 default: 627 return super.onCreateDialog(id, args); 628 629 } 630 } 631 updateInterface()632 void updateInterface() { 633 findViewById(R.id.restricted_icon).setVisibility(View.GONE); 634 mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager())); 635 mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager())); 636 try { 637 mAdminDescription.setText( 638 mDeviceAdmin.loadDescription(getPackageManager())); 639 mAdminDescription.setVisibility(View.VISIBLE); 640 } catch (Resources.NotFoundException e) { 641 mAdminDescription.setVisibility(View.GONE); 642 } 643 if (!TextUtils.isEmpty(mAddMsgText)) { 644 mAddMsg.setText(mAddMsgText); 645 mAddMsg.setVisibility(View.VISIBLE); 646 } else { 647 mAddMsg.setVisibility(View.GONE); 648 mAddMsgExpander.setVisibility(View.GONE); 649 } 650 if (!mRefreshing && !mAddingProfileOwner 651 && mDPM.isAdminActive(mDeviceAdmin.getComponent())) { 652 mAdding = false; 653 final boolean isProfileOwner = 654 mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner()); 655 final boolean isManagedProfile = isManagedProfile(mDeviceAdmin); 656 if (isProfileOwner && isManagedProfile) { 657 // Profile owner in a managed profile, user can remove profile to disable admin. 658 mAdminWarning.setText(R.string.admin_profile_owner_message); 659 mActionButton.setText(R.string.remove_managed_profile_label); 660 661 final EnforcedAdmin admin = getAdminEnforcingCantRemoveProfile(); 662 final boolean hasBaseRestriction = hasBaseCantRemoveProfileRestriction(); 663 if ((hasBaseRestriction && mDPM.isOrganizationOwnedDeviceWithManagedProfile()) 664 || (admin != null && !hasBaseRestriction)) { 665 findViewById(R.id.restricted_icon).setVisibility(View.VISIBLE); 666 } 667 mActionButton.setEnabled(admin == null && !hasBaseRestriction); 668 } else if (isProfileOwner || mDeviceAdmin.getComponent().equals( 669 mDPM.getDeviceOwnerComponentOnCallingUser())) { 670 // Profile owner in a user or device owner, user can't disable admin. 671 if (isProfileOwner) { 672 // Show profile owner in a user description. 673 mAdminWarning.setText(R.string.admin_profile_owner_user_message); 674 } else { 675 // Show device owner description. 676 if (isFinancedDevice()) { 677 mAdminWarning.setText(R.string.admin_financed_message); 678 } else { 679 mAdminWarning.setText(R.string.admin_device_owner_message); 680 } 681 } 682 mActionButton.setText(R.string.remove_device_admin); 683 mActionButton.setEnabled(false); 684 } else { 685 addDeviceAdminPolicies(false /* showDescription */); 686 mAdminWarning.setText(getString(R.string.device_admin_status, 687 mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel( 688 getPackageManager()))); 689 setTitle(R.string.active_device_admin_msg); 690 if (mUninstalling) { 691 mActionButton.setText(R.string.remove_and_uninstall_device_admin); 692 } else { 693 mActionButton.setText(R.string.remove_device_admin); 694 } 695 } 696 CharSequence supportMessage = mDPM.getLongSupportMessageForUser( 697 mDeviceAdmin.getComponent(), UserHandle.myUserId()); 698 if (!TextUtils.isEmpty(supportMessage)) { 699 mSupportMessage.setText(supportMessage); 700 mSupportMessage.setVisibility(View.VISIBLE); 701 } else { 702 mSupportMessage.setVisibility(View.GONE); 703 } 704 } else { 705 addDeviceAdminPolicies(true /* showDescription */); 706 mAdminWarning.setText(getString(R.string.device_admin_warning, 707 mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager()))); 708 setTitle(getText(R.string.add_device_admin_msg)); 709 mActionButton.setText(getText(R.string.add_device_admin)); 710 if (isAdminUninstallable()) { 711 mUninstallButton.setVisibility(View.VISIBLE); 712 } 713 mSupportMessage.setVisibility(View.GONE); 714 mAdding = true; 715 } 716 } 717 getAdminEnforcingCantRemoveProfile()718 private EnforcedAdmin getAdminEnforcingCantRemoveProfile() { 719 // Removing a managed profile is disallowed if DISALLOW_REMOVE_MANAGED_PROFILE 720 // is set in the parent rather than the user itself. 721 return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(this, 722 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, getParentUserId()); 723 } 724 hasBaseCantRemoveProfileRestriction()725 private boolean hasBaseCantRemoveProfileRestriction() { 726 return RestrictedLockUtilsInternal.hasBaseUserRestriction(this, 727 UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, getParentUserId()); 728 } 729 getParentUserId()730 private int getParentUserId() { 731 return UserManager.get(this).getProfileParent(UserHandle.myUserId()).id; 732 } 733 addDeviceAdminPolicies(boolean showDescription)734 private void addDeviceAdminPolicies(boolean showDescription) { 735 if (!mAdminPoliciesInitialized) { 736 boolean isAdminUser = UserManager.get(this).isAdminUser(); 737 for (DeviceAdminInfo.PolicyInfo pi : mDeviceAdmin.getUsedPolicies()) { 738 int descriptionId = isAdminUser ? pi.description : pi.descriptionForSecondaryUsers; 739 int labelId = isAdminUser ? pi.label : pi.labelForSecondaryUsers; 740 View view = getPermissionItemView(getText(labelId), 741 showDescription ? getText(descriptionId) : ""); 742 mAdminPolicies.addView(view); 743 } 744 mAdminPoliciesInitialized = true; 745 } 746 } 747 748 /** 749 * Utility to retrieve a view displaying a single permission. This provides 750 * the UI layout for permissions. 751 */ getPermissionItemView(CharSequence grpName, CharSequence description)752 private View getPermissionItemView(CharSequence grpName, CharSequence description) { 753 Drawable icon = this.getDrawable(com.android.internal.R.drawable.ic_text_dot); 754 View permView = mLayoutInflaternflater.inflate(R.layout.app_permission_item, null); 755 TextView permGrpView = permView.findViewById(R.id.permission_group); 756 TextView permDescView = permView.findViewById(R.id.permission_list); 757 ImageView imgView = (ImageView) permView.findViewById(R.id.perm_icon); 758 759 imgView.setImageDrawable(icon); 760 if (grpName != null) { 761 permGrpView.setText(grpName); 762 permDescView.setText(description); 763 } else { 764 permGrpView.setText(description); 765 permDescView.setVisibility(View.GONE); 766 } 767 return permView; 768 } 769 toggleMessageEllipsis(View v)770 void toggleMessageEllipsis(View v) { 771 TextView tv = (TextView) v; 772 773 mAddMsgEllipsized = ! mAddMsgEllipsized; 774 tv.setEllipsize(mAddMsgEllipsized ? TruncateAt.END : null); 775 tv.setMaxLines(mAddMsgEllipsized ? getEllipsizedLines() : MAX_ADD_MSG_LINES); 776 777 mAddMsgExpander.setImageResource(mAddMsgEllipsized ? 778 com.android.internal.R.drawable.expander_ic_minimized : 779 com.android.internal.R.drawable.expander_ic_maximized); 780 } 781 getEllipsizedLines()782 int getEllipsizedLines() { 783 Display d = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)) 784 .getDefaultDisplay(); 785 786 return d.getHeight() > d.getWidth() ? 787 MAX_ADD_MSG_LINES_PORTRAIT : MAX_ADD_MSG_LINES_LANDSCAPE; 788 } 789 790 /** 791 * @return true if adminInfo is running in a managed profile. 792 */ isManagedProfile(DeviceAdminInfo adminInfo)793 private boolean isManagedProfile(DeviceAdminInfo adminInfo) { 794 UserManager um = UserManager.get(this); 795 UserInfo info = um.getUserInfo( 796 UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid)); 797 return info != null ? info.isManagedProfile() : false; 798 } 799 isFinancedDevice()800 private boolean isFinancedDevice() { 801 return mDPM.isDeviceManaged() && mDPM.getDeviceOwnerType( 802 mDPM.getDeviceOwnerComponentOnAnyUser()) == DEVICE_OWNER_TYPE_FINANCED; 803 } 804 805 /** 806 * @return an {@link Optional} containing the admin with a given package name, if it exists, 807 * or {@link Optional#empty()} otherwise. 808 */ findAdminWithPackageName(String packageName)809 private Optional<ComponentName> findAdminWithPackageName(String packageName) { 810 List<ComponentName> admins = mDPM.getActiveAdmins(); 811 if (admins == null) { 812 return Optional.empty(); 813 } 814 return admins.stream().filter(i -> i.getPackageName().equals(packageName)).findAny(); 815 } 816 isAdminUninstallable()817 private boolean isAdminUninstallable() { 818 // System apps can't be uninstalled. 819 return !mDeviceAdmin.getActivityInfo().applicationInfo.isSystemApp(); 820 } 821 } 822