1 /*
2  * Copyright (C) 2017 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 package com.android.settings.system;
17 
18 import android.Manifest;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.ResolveInfo;
24 import android.os.UserManager;
25 import android.util.Log;
26 
27 import androidx.activity.result.ActivityResultLauncher;
28 import androidx.activity.result.contract.ActivityResultContracts;
29 import androidx.preference.Preference;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.settings.Settings;
33 import com.android.settings.core.BasePreferenceController;
34 import com.android.settings.factory_reset.Flags;
35 
36 public class FactoryResetPreferenceController extends BasePreferenceController {
37 
38     private static final String TAG = "FactoryResetPreference";
39 
40     @VisibleForTesting
41     static final String ACTION_PREPARE_FACTORY_RESET =
42             "com.android.settings.ACTION_PREPARE_FACTORY_RESET";
43 
44     private final UserManager mUm;
45 
46     @VisibleForTesting
47     ActivityResultLauncher<Intent> mFactoryResetPreparationLauncher;
48 
FactoryResetPreferenceController(Context context, String preferenceKey)49     public FactoryResetPreferenceController(Context context, String preferenceKey) {
50         super(context, preferenceKey);
51         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
52     }
53 
54     /** Hide "Factory reset" settings for secondary users. */
55     @Override
getAvailabilityStatus()56     public int getAvailabilityStatus() {
57         return mUm.isAdminUser() ? AVAILABLE : DISABLED_FOR_USER;
58     }
59 
60     @Override
handlePreferenceTreeClick(Preference preference)61     public boolean handlePreferenceTreeClick(Preference preference) {
62         if (mPreferenceKey.equals(preference.getKey())) {
63             if (Flags.enableFactoryResetWizard()) {
64                 startFactoryResetPreparationActivity();
65             } else {
66                 startFactoryResetActivity();
67             }
68             return true;
69         }
70         return false;
71     }
72 
startFactoryResetPreparationActivity()73     private void startFactoryResetPreparationActivity() {
74         Intent prepareFactoryResetIntent = getPrepareFactoryResetIntent();
75         if (prepareFactoryResetIntent != null && mFactoryResetPreparationLauncher != null) {
76             mFactoryResetPreparationLauncher.launch(prepareFactoryResetIntent);
77         } else {
78             startFactoryResetActivity();
79         }
80     }
81 
82     // We check that the activity that can handle the factory reset preparation action is indeed
83     // a system app with proper permissions.
getPrepareFactoryResetIntent()84     private Intent getPrepareFactoryResetIntent() {
85         final Intent prepareFactoryResetWizardRequest = new Intent(ACTION_PREPARE_FACTORY_RESET);
86         final PackageManager pm = mContext.getPackageManager();
87         final ResolveInfo resolution = pm.resolveActivity(prepareFactoryResetWizardRequest, 0);
88         if (resolution != null
89                 && resolution.activityInfo != null) {
90             String packageName = resolution.activityInfo.packageName;
91             PackageInfo factoryResetWizardPackageInfo;
92             try {
93                 factoryResetWizardPackageInfo = pm.getPackageInfo(packageName,
94                         PackageManager.GET_PERMISSIONS);
95             } catch (PackageManager.NameNotFoundException e) {
96                 Log.e(TAG, "Unable to resolve a Factory Reset Handler Application");
97                 return null;
98             }
99             if (factoryResetWizardPackageInfo.requestedPermissions == null
100                     || factoryResetWizardPackageInfo.requestedPermissions.length == 0) {
101                 Log.e(TAG, "Factory Reset Handler has no permissions requested.");
102                 return null;
103             }
104             for (int i = 0; i < factoryResetWizardPackageInfo.requestedPermissions.length; i++) {
105                 String permission = factoryResetWizardPackageInfo.requestedPermissions[i];
106                 boolean isGranted =
107                         (factoryResetWizardPackageInfo.requestedPermissionsFlags[i]
108                                 & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
109                 if (permission.equals(Manifest.permission.PREPARE_FACTORY_RESET) && isGranted) {
110                     return prepareFactoryResetWizardRequest;
111                 }
112             }
113             return prepareFactoryResetWizardRequest;
114         }
115         Log.i(TAG, "Unable to resolve a Factory Reset Handler Activity");
116         return null;
117     }
118 
setFragment(ResetDashboardFragment fragment)119     void setFragment(ResetDashboardFragment fragment) {
120         if (Flags.enableFactoryResetWizard()) {
121             mFactoryResetPreparationLauncher = fragment.registerForActivityResult(
122                     new ActivityResultContracts.StartActivityForResult(),
123                     result -> {
124                         startFactoryResetActivity();
125                     });
126         }
127     }
128 
startFactoryResetActivity()129     private void startFactoryResetActivity() {
130         final Intent intent = new Intent(mContext, Settings.FactoryResetActivity.class);
131         mContext.startActivity(intent);
132     }
133 }
134