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