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