• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.car.settings.applications;
18 
19 import static android.app.Activity.RESULT_FIRST_USER;
20 import static android.app.Activity.RESULT_OK;
21 
22 import static com.android.car.settings.applications.ApplicationsUtils.isKeepEnabledPackage;
23 import static com.android.car.settings.applications.ApplicationsUtils.isProfileOrDeviceOwner;
24 import static com.android.car.settings.common.ActionButtonsPreference.ActionButtons;
25 import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
26 import static com.android.car.settings.enterprise.EnterpriseUtils.BLOCKED_UNINSTALL_APP;
27 
28 import android.app.Activity;
29 import android.app.ActivityManager;
30 import android.app.admin.DevicePolicyManager;
31 import android.car.drivingstate.CarUxRestrictions;
32 import android.content.BroadcastReceiver;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.pm.ApplicationInfo;
37 import android.content.pm.PackageInfo;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.net.Uri;
41 import android.os.Bundle;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.util.ArraySet;
45 import android.view.View;
46 import android.widget.Toast;
47 
48 import androidx.annotation.Nullable;
49 import androidx.annotation.VisibleForTesting;
50 
51 import com.android.car.settings.R;
52 import com.android.car.settings.common.ActionButtonInfo;
53 import com.android.car.settings.common.ActionButtonsPreference;
54 import com.android.car.settings.common.ActivityResultCallback;
55 import com.android.car.settings.common.ConfirmationDialogFragment;
56 import com.android.car.settings.common.FragmentController;
57 import com.android.car.settings.common.Logger;
58 import com.android.car.settings.common.PreferenceController;
59 import com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment;
60 import com.android.car.settings.enterprise.DeviceAdminAddActivity;
61 import com.android.car.settings.enterprise.EnterpriseUtils;
62 import com.android.car.settings.profiles.ProfileHelper;
63 import com.android.settingslib.Utils;
64 import com.android.settingslib.applications.ApplicationsState;
65 
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.List;
69 import java.util.Set;
70 
71 /**
72  * Shows actions associated with an application, like uninstall and forceStop.
73  *
74  * <p>To uninstall an app, it must <i>not</i> be:
75  * <ul>
76  * <li>a system bundled app
77  * <li>system signed
78  * <li>managed by an active admin from a device policy
79  * <li>a device or profile owner
80  * <li>the only home app
81  * <li>the default home app
82  * <li>for a user with the {@link UserManager#DISALLOW_APPS_CONTROL} restriction
83  * <li>for a user with the {@link UserManager#DISALLOW_UNINSTALL_APPS} restriction
84  * </ul>
85  *
86  * <p>For apps that cannot be uninstalled, a disable option is shown instead (or enable if the app
87  * is already disabled).
88  */
89 public class ApplicationActionButtonsPreferenceController extends
90         PreferenceController<ActionButtonsPreference> implements ActivityResultCallback {
91     private static final Logger LOG = new Logger(
92             ApplicationActionButtonsPreferenceController.class);
93 
94     private static final List<String> FORCE_STOP_RESTRICTIONS =
95             Arrays.asList(UserManager.DISALLOW_APPS_CONTROL);
96     private static final List<String> UNINSTALL_RESTRICTIONS =
97             Arrays.asList(UserManager.DISALLOW_UNINSTALL_APPS, UserManager.DISALLOW_APPS_CONTROL);
98     private static final List<String> DISABLE_RESTRICTIONS =
99             Arrays.asList(UserManager.DISALLOW_APPS_CONTROL);
100 
101     @VisibleForTesting
102     static final String DISABLE_CONFIRM_DIALOG_TAG =
103             "com.android.car.settings.applications.DisableConfirmDialog";
104     @VisibleForTesting
105     static final String FORCE_STOP_CONFIRM_DIALOG_TAG =
106             "com.android.car.settings.applications.ForceStopConfirmDialog";
107 
108     @VisibleForTesting
109     static final int UNINSTALL_REQUEST_CODE = 10;
110 
111     @VisibleForTesting
112     static final int UNINSTALL_DEVICE_ADMIN_REQUEST_CODE = 11;
113 
114     private DevicePolicyManager mDpm;
115     private PackageManager mPm;
116     private UserManager mUserManager;
117     private ProfileHelper mProfileHelper;
118     private ApplicationsState.Session mSession;
119 
120     private ApplicationsState.AppEntry mAppEntry;
121     private ApplicationsState mApplicationsState;
122     private String mPackageName;
123     private PackageInfo mPackageInfo;
124 
125     private String mRestriction;
126 
127     @VisibleForTesting
128     final ConfirmationDialogFragment.ConfirmListener mForceStopConfirmListener =
129             new ConfirmationDialogFragment.ConfirmListener() {
130                 @Override
131                 public void onConfirm(@Nullable Bundle arguments) {
132                     LOG.d("Stopping package " + mPackageName);
133                     getContext().getSystemService(ActivityManager.class)
134                             .forceStopPackage(mPackageName);
135                     int userId = UserHandle.getUserId(mAppEntry.info.uid);
136                     mApplicationsState.invalidatePackage(mPackageName, userId);
137                     Toast.makeText(getContext(), getContext().getResources()
138                             .getString(R.string.force_stop_success_toast_text,
139                                     mAppEntry.info.loadLabel(mPm)), Toast.LENGTH_LONG).show();
140                 }
141             };
142 
143     private final View.OnClickListener mForceStopClickListener = i -> {
144         if (ignoreActionBecauseItsDisabledByAdmin(FORCE_STOP_RESTRICTIONS)) return;
145         ConfirmationDialogFragment dialogFragment =
146                 new ConfirmationDialogFragment.Builder(getContext())
147                         .setTitle(R.string.force_stop_dialog_title)
148                         .setMessage(R.string.force_stop_dialog_text)
149                         .setPositiveButton(android.R.string.ok,
150                                 mForceStopConfirmListener)
151                         .setNegativeButton(android.R.string.cancel, /* rejectListener= */ null)
152                         .build();
153         getFragmentController().showDialog(dialogFragment, FORCE_STOP_CONFIRM_DIALOG_TAG);
154     };
155 
156     @VisibleForTesting
157     final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
158         @Override
159         public void onReceive(Context context, Intent intent) {
160             boolean enabled = getResultCode() != Activity.RESULT_CANCELED;
161             LOG.d("Got broadcast response: Restart status for " + mPackageName + " " + enabled);
162             updateForceStopButtonInner(enabled);
163         }
164     };
165 
166     @VisibleForTesting
167     final ConfirmationDialogFragment.ConfirmListener mDisableConfirmListener = i -> {
168         mPm.setApplicationEnabledSetting(mPackageName,
169                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, /* flags= */ 0);
170         updateUninstallButtonInner(false);
171     };
172 
173     private final View.OnClickListener mDisableClickListener = i -> {
174         if (ignoreActionBecauseItsDisabledByAdmin(DISABLE_RESTRICTIONS)) return;
175         ConfirmationDialogFragment dialogFragment =
176                 new ConfirmationDialogFragment.Builder(getContext())
177                         .setMessage(getContext().getString(R.string.app_disable_dialog_text))
178                         .setPositiveButton(R.string.app_disable_dialog_positive,
179                                 mDisableConfirmListener)
180                         .setNegativeButton(android.R.string.cancel, /* rejectListener= */ null)
181                         .build();
182         getFragmentController().showDialog(dialogFragment, DISABLE_CONFIRM_DIALOG_TAG);
183     };
184 
185     private final View.OnClickListener mEnableClickListener = i -> {
186         if (ignoreActionBecauseItsDisabledByAdmin(DISABLE_RESTRICTIONS)) return;
187         mPm.setApplicationEnabledSetting(mPackageName,
188                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, /* flags= */ 0);
189         updateUninstallButtonInner(true);
190     };
191 
192     private final View.OnClickListener mUninstallClickListener = i -> {
193         if (ignoreActionBecauseItsDisabledByAdmin(UNINSTALL_RESTRICTIONS)) return;
194         Uri packageUri = Uri.parse("package:" + mPackageName);
195         if (mDpm.packageHasActiveAdmins(mPackageName)) {
196             // Show Device Admin app details screen to deactivate the device admin before it can
197             // be uninstalled.
198             Intent deviceAdminIntent = new Intent(getContext(), DeviceAdminAddActivity.class)
199                     .putExtra(DeviceAdminAddActivity.EXTRA_DEVICE_ADMIN_PACKAGE_NAME, mPackageName);
200             getFragmentController().startActivityForResult(deviceAdminIntent,
201                     UNINSTALL_DEVICE_ADMIN_REQUEST_CODE, /* callback= */ this);
202         } else {
203             Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
204             uninstallIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
205             getFragmentController().startActivityForResult(uninstallIntent, UNINSTALL_REQUEST_CODE,
206                     /* callback= */ this);
207         }
208     };
209 
210     private final ApplicationsState.Callbacks mApplicationStateCallbacks =
211             new ApplicationsState.Callbacks() {
212                 @Override
213                 public void onRunningStateChanged(boolean running) {
214                 }
215 
216                 @Override
217                 public void onPackageListChanged() {
218                     refreshUi();
219                 }
220 
221                 @Override
222                 public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
223                 }
224 
225                 @Override
226                 public void onPackageIconChanged() {
227                 }
228 
229                 @Override
230                 public void onPackageSizeChanged(String packageName) {
231                 }
232 
233                 @Override
234                 public void onAllSizesComputed() {
235                 }
236 
237                 @Override
238                 public void onLauncherInfoChanged() {
239                 }
240 
241                 @Override
242                 public void onLoadEntriesCompleted() {
243                 }
244             };
245 
ApplicationActionButtonsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)246     public ApplicationActionButtonsPreferenceController(Context context, String preferenceKey,
247             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
248         super(context, preferenceKey, fragmentController, uxRestrictions);
249         mDpm = context.getSystemService(DevicePolicyManager.class);
250         mPm = context.getPackageManager();
251         mUserManager = UserManager.get(context);
252         mProfileHelper = ProfileHelper.getInstance(context);
253     }
254 
255     @Override
getPreferenceType()256     protected Class<ActionButtonsPreference> getPreferenceType() {
257         return ActionButtonsPreference.class;
258     }
259 
260     /** Sets the {@link ApplicationsState.AppEntry} which is used to load the app name and icon. */
setAppEntry( ApplicationsState.AppEntry appEntry)261     public ApplicationActionButtonsPreferenceController setAppEntry(
262             ApplicationsState.AppEntry appEntry) {
263         mAppEntry = appEntry;
264         return this;
265     }
266 
267     /** Sets the {@link ApplicationsState} which is used to load the app name and icon. */
setAppState( ApplicationsState applicationsState)268     public ApplicationActionButtonsPreferenceController setAppState(
269             ApplicationsState applicationsState) {
270         mApplicationsState = applicationsState;
271         return this;
272     }
273 
274     /**
275      * Set the packageName, which is used to perform actions on a particular package.
276      */
setPackageName(String packageName)277     public ApplicationActionButtonsPreferenceController setPackageName(String packageName) {
278         mPackageName = packageName;
279         return this;
280     }
281 
282     @Override
checkInitialized()283     protected void checkInitialized() {
284         if (mAppEntry == null || mApplicationsState == null || mPackageName == null) {
285             throw new IllegalStateException(
286                     "AppEntry, AppState, and PackageName should be set before calling this "
287                             + "function");
288         }
289     }
290 
291     @Override
onCreateInternal()292     protected void onCreateInternal() {
293         ConfirmationDialogFragment.resetListeners(
294                 (ConfirmationDialogFragment) getFragmentController().findDialogByTag(
295                         DISABLE_CONFIRM_DIALOG_TAG),
296                 mDisableConfirmListener,
297                 /* rejectListener= */ null,
298                 /* neutralListener= */ null);
299         ConfirmationDialogFragment.resetListeners(
300                 (ConfirmationDialogFragment) getFragmentController().findDialogByTag(
301                         FORCE_STOP_CONFIRM_DIALOG_TAG),
302                 mForceStopConfirmListener,
303                 /* rejectListener= */ null,
304                 /* neutralListener= */ null);
305         getPreference().getButton(ActionButtons.BUTTON2)
306                 .setText(R.string.force_stop)
307                 .setIcon(R.drawable.ic_warning)
308                 .setOnClickListener(mForceStopClickListener)
309                 .setEnabled(false);
310         mSession = mApplicationsState.newSession(mApplicationStateCallbacks);
311     }
312 
313     @Override
onStartInternal()314     protected void onStartInternal() {
315         mSession.onResume();
316     }
317 
318     @Override
onStopInternal()319     protected void onStopInternal() {
320         mSession.onPause();
321     }
322 
323     @Override
updateState(ActionButtonsPreference preference)324     protected void updateState(ActionButtonsPreference preference) {
325         refreshAppEntry();
326         if (mAppEntry == null) {
327             getFragmentController().goBack();
328             return;
329         }
330         updateForceStopButton();
331         updateUninstallButton();
332     }
333 
refreshAppEntry()334     private void refreshAppEntry() {
335         mAppEntry = mApplicationsState.getEntry(mPackageName, UserHandle.myUserId());
336         if (mAppEntry != null) {
337             try {
338                 mPackageInfo = mPm.getPackageInfo(mPackageName,
339                         PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_ANY_USER
340                                 | PackageManager.GET_SIGNATURES | PackageManager.GET_PERMISSIONS);
341             } catch (PackageManager.NameNotFoundException e) {
342                 LOG.e("Exception when retrieving package:" + mPackageName, e);
343                 mPackageInfo = null;
344             }
345         } else {
346             mPackageInfo = null;
347         }
348     }
349 
updateForceStopButton()350     private void updateForceStopButton() {
351         if (mDpm.packageHasActiveAdmins(mPackageName)) {
352             updateForceStopButtonInner(/* enabled= */ false);
353         } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
354             // If the app isn't explicitly stopped, then always show the force stop button.
355             updateForceStopButtonInner(/* enabled= */ true);
356         } else {
357             Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
358                     Uri.fromParts("package", mPackageName, /* fragment= */ null));
359             intent.putExtra(Intent.EXTRA_PACKAGES, new String[]{mPackageName});
360             intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
361             intent.putExtra(Intent.EXTRA_USER_HANDLE,
362                     UserHandle.getUserId(mAppEntry.info.uid));
363             LOG.d("Sending broadcast to query restart status for " + mPackageName);
364             getContext().sendOrderedBroadcastAsUser(intent,
365                     UserHandle.CURRENT,
366                     android.Manifest.permission.HANDLE_QUERY_PACKAGE_RESTART,
367                     mCheckKillProcessesReceiver,
368                     /* scheduler= */ null,
369                     Activity.RESULT_CANCELED,
370                     /* initialData= */ null,
371                     /* initialExtras= */ null);
372         }
373     }
374 
updateForceStopButtonInner(boolean enabled)375     private void updateForceStopButtonInner(boolean enabled) {
376         if (enabled) {
377             Boolean shouldDisable = shouldDisableButtonBecauseOfUserRestriction("Force Stop",
378                     UserManager.DISALLOW_APPS_CONTROL);
379             if (shouldDisable != null) {
380                 if (shouldDisable) {
381                     enabled = false;
382                 } else {
383                     mRestriction = UserManager.DISALLOW_APPS_CONTROL;
384                 }
385             }
386         }
387 
388         getPreference().getButton(ActionButtons.BUTTON2).setEnabled(enabled);
389     }
390 
updateUninstallButtonInner(boolean isAppEnabled)391     private void updateUninstallButtonInner(boolean isAppEnabled) {
392         ActionButtonInfo uninstallButton = getPreference().getButton(ActionButtons.BUTTON1);
393         if (isBundledApp()) {
394             if (isAppEnabled) {
395                 uninstallButton.setText(R.string.disable_text).setIcon(
396                         R.drawable.ic_block).setOnClickListener(mDisableClickListener);
397             } else {
398                 uninstallButton.setText(R.string.enable_text).setIcon(
399                         R.drawable.ic_check_circle).setOnClickListener(mEnableClickListener);
400             }
401         } else {
402             uninstallButton.setText(R.string.uninstall_text).setIcon(
403                     R.drawable.ic_delete).setOnClickListener(mUninstallClickListener);
404         }
405 
406         uninstallButton.setEnabled(!shouldDisableUninstallButton());
407     }
408 
updateUninstallButton()409     private void updateUninstallButton() {
410         updateUninstallButtonInner(isAppEnabled());
411     }
412 
shouldDisableUninstallButton()413     private boolean shouldDisableUninstallButton() {
414         if (shouldDisableUninstallForHomeApp()) {
415             LOG.d("Uninstall disabled for home app");
416             return true;
417         }
418 
419         if (isAppEnabled() && isKeepEnabledPackage(getContext(), mPackageName)) {
420             LOG.d("Disable button disabled for keep enabled package");
421             return true;
422         }
423 
424         if (Utils.isSystemPackage(getContext().getResources(), mPm, mPackageInfo)) {
425             LOG.d("Uninstall disabled for system package");
426             return true;
427         }
428 
429         // We don't allow uninstalling profile/device owner on any profile because if it's a system
430         // app, "uninstall" is actually "downgrade to the system version + disable", and
431         // "downgrade" will clear data on all profiles.
432         if (isProfileOrDeviceOwner(mPackageName, mDpm, mProfileHelper)) {
433             LOG.d("Uninstall disabled because package is profile or device owner");
434             return true;
435         }
436 
437         if (mDpm.isUninstallInQueue(mPackageName)) {
438             LOG.d("Uninstall disabled because intent is already queued");
439             return true;
440         }
441 
442         Boolean shouldDisable = shouldDisableButtonBecauseOfUserRestriction("Uninstall",
443                 UserManager.DISALLOW_APPS_CONTROL);
444         if (shouldDisable != null) return shouldDisable;
445 
446         shouldDisable = shouldDisableButtonBecauseOfUserRestriction("Uninstall",
447                 UserManager.DISALLOW_UNINSTALL_APPS);
448         if (shouldDisable != null) return shouldDisable;
449 
450         return false;
451     }
452 
453     /**
454      * Checks whether a button should be disabled because the user has the given restriction
455      * (and whether the restriction was was set by a device admin).
456      *
457      * @param button action name (for logging purposes)
458      * @param restriction user restriction
459      *
460      * @return {@code null} if the user doesn't have the restriction, {@value Boolean#TRUE} if it
461      * should be disabled because of {@link UserManager} restrictions, or {@value Boolean#FALSE} if
462      * should not be disabled because of {@link DevicePolicyManager} restrictions (in which case
463      * {@link #mRestriction} is updated with the restriction).
464      */
465     @Nullable
shouldDisableButtonBecauseOfUserRestriction(String button, String restriction)466     private Boolean shouldDisableButtonBecauseOfUserRestriction(String button, String restriction) {
467         if (!mUserManager.hasUserRestriction(restriction)) return null;
468 
469         UserHandle user = UserHandle.getUserHandleForUid(mAppEntry.info.uid);
470 
471         if (mUserManager.hasBaseUserRestriction(restriction, user)) {
472             LOG.d(button + " disabled because " + user + " has " + restriction + " restriction");
473             return Boolean.TRUE;
474         }
475 
476         LOG.d(button + " NOT disabled because " + user + " has " + restriction + " restriction but "
477                 + "it was set by a device admin (it will show a dialog explaining that instead)");
478         mRestriction = restriction;
479         return Boolean.FALSE;
480     }
481 
482     /**
483      * Returns {@code true} if the package is a Home app that should not be uninstalled. We don't
484      * risk downgrading bundled home apps because that can interfere with home-key resolution. We
485      * can't allow removal of the only home app, and we don't want to allow removal of an
486      * explicitly preferred home app. The user can go to Home settings and pick a different app,
487      * after which we'll permit removal of the now-not-default app.
488      */
shouldDisableUninstallForHomeApp()489     private boolean shouldDisableUninstallForHomeApp() {
490         Set<String> homePackages = new ArraySet<>();
491         // Get list of "home" apps and trace through any meta-data references.
492         List<ResolveInfo> homeActivities = new ArrayList<>();
493         ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
494         for (int i = 0; i < homeActivities.size(); i++) {
495             ResolveInfo ri = homeActivities.get(i);
496             String activityPkg = ri.activityInfo.packageName;
497             homePackages.add(activityPkg);
498 
499             // Also make sure to include anything proxying for the home app.
500             Bundle metadata = ri.activityInfo.metaData;
501             if (metadata != null) {
502                 String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
503                 if (signaturesMatch(metaPkg, activityPkg)) {
504                     homePackages.add(metaPkg);
505                 }
506             }
507         }
508 
509         if (homePackages.contains(mPackageName)) {
510             if (isBundledApp()) {
511                 // Don't risk a downgrade.
512                 return true;
513             } else if (currentDefaultHome == null) {
514                 // No preferred default. Permit uninstall only when there is more than one
515                 // candidate.
516                 return (homePackages.size() == 1);
517             } else {
518                 // Explicit default home app. Forbid uninstall of that one, but permit it for
519                 // installed-but-inactive ones.
520                 return mPackageName.equals(currentDefaultHome.getPackageName());
521             }
522         } else {
523             // Not a home app.
524             return false;
525         }
526     }
527 
signaturesMatch(String pkg1, String pkg2)528     private boolean signaturesMatch(String pkg1, String pkg2) {
529         if (pkg1 != null && pkg2 != null) {
530             try {
531                 int match = mPm.checkSignatures(pkg1, pkg2);
532                 if (match >= PackageManager.SIGNATURE_MATCH) {
533                     return true;
534                 }
535             } catch (Exception e) {
536                 // e.g. package not found during lookup. Possibly bad input.
537                 // Just return false as this isn't a reason to crash given the use case.
538             }
539         }
540         return false;
541     }
542 
isBundledApp()543     private boolean isBundledApp() {
544         return (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
545     }
546 
isAppEnabled()547     private boolean isAppEnabled() {
548         return mAppEntry.info.enabled && !(mAppEntry.info.enabledSetting
549                 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
550     }
551 
552     @Override
processActivityResult(int requestCode, int resultCode, @Nullable Intent data)553     public void processActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
554         if (requestCode == UNINSTALL_REQUEST_CODE
555                 || requestCode == UNINSTALL_DEVICE_ADMIN_REQUEST_CODE) {
556             if (resultCode == RESULT_OK) {
557                 getFragmentController().goBack();
558             } else if (resultCode == RESULT_FIRST_USER) {
559                 showUninstallBlockedByAdminDialog();
560                 LOG.e("Uninstall failed");
561             }
562         }
563     }
564 
showUninstallBlockedByAdminDialog()565     private void showUninstallBlockedByAdminDialog() {
566         getFragmentController().showDialog(
567                 EnterpriseUtils.getActionDisabledByAdminDialog(getContext(),
568                         BLOCKED_UNINSTALL_APP, mPackageName),
569                 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG);
570     }
571 
ignoreActionBecauseItsDisabledByAdmin(List<String> restrictions)572     private boolean ignoreActionBecauseItsDisabledByAdmin(List<String> restrictions) {
573         if (mRestriction == null || !restrictions.contains(mRestriction)) return false;
574 
575         LOG.d("Ignoring action because of " + mRestriction);
576         getFragmentController().showDialog(ActionDisabledByAdminDialogFragment.newInstance(
577                 mRestriction, UserHandle.myUserId()), DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG);
578         return true;
579     }
580 }
581