1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.settings.applications.manageapplications;
17 
18 import static android.net.NetworkPolicyManager.POLICY_NONE;
19 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
20 
21 import android.app.ActivityManager;
22 import android.app.AppOpsManager;
23 import android.app.INotificationManager;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.IPackageManager;
28 import android.content.pm.PackageManager;
29 import android.net.NetworkPolicyManager;
30 import android.os.AsyncTask;
31 import android.os.Bundle;
32 import android.os.RemoteException;
33 import android.os.ServiceManager;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.util.Log;
37 
38 import androidx.appcompat.app.AlertDialog;
39 
40 import com.android.settings.R;
41 import com.android.settings.fuelgauge.BatteryOptimizeUtils;
42 import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
43 
44 import java.util.Arrays;
45 import java.util.List;
46 
47 public class ResetAppsHelper implements DialogInterface.OnClickListener,
48         DialogInterface.OnDismissListener {
49 
50     private static final String EXTRA_RESET_DIALOG = "resetDialog";
51     private static final String TAG = "ResetAppsHelper";
52 
53     private final PackageManager mPm;
54     private final IPackageManager mIPm;
55     private final INotificationManager mNm;
56     private final NetworkPolicyManager mNpm;
57     private final AppOpsManager mAom;
58     private final Context mContext;
59     private final UserManager mUm;
60 
61     private AlertDialog mResetDialog;
62 
ResetAppsHelper(Context context)63     public ResetAppsHelper(Context context) {
64         mContext = context;
65         mPm = context.getPackageManager();
66         mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
67         mNm = INotificationManager.Stub.asInterface(
68                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
69         mNpm = NetworkPolicyManager.from(context);
70         mAom = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
71         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
72     }
73 
onRestoreInstanceState(Bundle savedInstanceState)74     public void onRestoreInstanceState(Bundle savedInstanceState) {
75         if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
76             buildResetDialog();
77         }
78     }
79 
onSaveInstanceState(Bundle outState)80     public void onSaveInstanceState(Bundle outState) {
81         if (mResetDialog != null) {
82             outState.putBoolean(EXTRA_RESET_DIALOG, true);
83         }
84     }
85 
stop()86     public void stop() {
87         if (mResetDialog != null) {
88             mResetDialog.dismiss();
89             mResetDialog = null;
90         }
91     }
92 
buildResetDialog()93     void buildResetDialog() {
94         if (mResetDialog == null) {
95             mResetDialog = new AlertDialog.Builder(mContext)
96                     .setTitle(R.string.reset_app_preferences_title)
97                     .setMessage(R.string.reset_app_preferences_desc)
98                     .setPositiveButton(R.string.reset_app_preferences_button, this)
99                     .setNegativeButton(R.string.cancel, null)
100                     .setOnDismissListener(this)
101                     .show();
102         }
103     }
104 
105     @Override
onDismiss(DialogInterface dialog)106     public void onDismiss(DialogInterface dialog) {
107         if (mResetDialog == dialog) {
108             mResetDialog = null;
109         }
110     }
111 
112     @Override
onClick(DialogInterface dialog, int which)113     public void onClick(DialogInterface dialog, int which) {
114         if (mResetDialog == dialog) {
115             resetApps();
116         }
117     }
118 
119     /** Resets the app preferences. */
resetApps()120     public void resetApps() {
121         AsyncTask.execute(() -> {
122             final List<String> allowList = Arrays.asList(
123                     mContext.getResources().getStringArray(
124                             R.array.config_skip_reset_apps_package_name));
125             for (UserHandle userHandle : mUm.getEnabledProfiles()) {
126                 final int userId = userHandle.getIdentifier();
127                 final List<ApplicationInfo> apps = mPm.getInstalledApplicationsAsUser(
128                         PackageManager.GET_DISABLED_COMPONENTS, userId);
129                 for (ApplicationInfo app : apps) {
130                     if (allowList.contains(app.packageName)) {
131                         continue;
132                     }
133                     try {
134                         mNm.clearData(app.packageName, app.uid, false);
135                     } catch (RemoteException ex) {
136                     }
137                     if (!app.enabled) {
138                         try {
139                             if (mIPm.getApplicationEnabledSetting(app.packageName, userId)
140                                     == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
141                                 mIPm.setApplicationEnabledSetting(app.packageName,
142                                         PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
143                                         PackageManager.DONT_KILL_APP,
144                                         userId,
145                                         mContext.getPackageName());
146                             }
147                         } catch (RemoteException e) {
148                             Log.e(TAG, "Error during reset disabled apps.", e);
149                         }
150                     }
151                 }
152             }
153             try {
154                 mIPm.resetApplicationPreferences(UserHandle.myUserId());
155             } catch (RemoteException e) {
156             }
157             mAom.resetAllModes();
158             BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom);
159             DynamicDenylistManager.getInstance(mContext)
160                     .resetDenylistIfNeeded(/* packageName= */ null, /* force= */ true);
161             final int[] restrictedUids = mNpm.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
162             final int currentUserId = ActivityManager.getCurrentUser();
163             for (int uid : restrictedUids) {
164                 // Only reset for current user
165                 if (UserHandle.getUserId(uid) == currentUserId) {
166                     mNpm.setUidPolicy(uid, POLICY_NONE);
167                 }
168             }
169         });
170     }
171 }
172