diff --git a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java index 708f8b7004d..6da3e529065 100644 --- a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java +++ b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java @@ -110,58 +110,57 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener, @Override public void onClick(DialogInterface dialog, int which) { - if (mResetDialog != dialog) { - return; + if (mResetDialog == dialog) { + resetApps(); } - AsyncTask.execute(new Runnable() { - @Override - public void run() { - final List allowList = Arrays.asList( - mContext.getResources().getStringArray( - R.array.config_skip_reset_apps_package_name)); - for (UserHandle userHandle : mUm.getEnabledProfiles()) { - final int userId = userHandle.getIdentifier(); - final List apps = mPm.getInstalledApplicationsAsUser( - PackageManager.GET_DISABLED_COMPONENTS, userId); - for (int i = 0; i < apps.size(); i++) { - ApplicationInfo app = apps.get(i); - if (allowList.contains(app.packageName)) { - continue; - } + } + + /** Resets the app preferences. */ + public void resetApps() { + AsyncTask.execute(() -> { + final List allowList = Arrays.asList( + mContext.getResources().getStringArray( + R.array.config_skip_reset_apps_package_name)); + for (UserHandle userHandle : mUm.getEnabledProfiles()) { + final int userId = userHandle.getIdentifier(); + final List apps = mPm.getInstalledApplicationsAsUser( + PackageManager.GET_DISABLED_COMPONENTS, userId); + for (ApplicationInfo app : apps) { + if (allowList.contains(app.packageName)) { + continue; + } + try { + mNm.clearData(app.packageName, app.uid, false); + } catch (RemoteException ex) { + } + if (!app.enabled) { try { - mNm.clearData(app.packageName, app.uid, false); - } catch (android.os.RemoteException ex) { - } - if (!app.enabled) { - try { - if (mIPm.getApplicationEnabledSetting(app.packageName, userId) - == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { - mIPm.setApplicationEnabledSetting(app.packageName, - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, - PackageManager.DONT_KILL_APP, - userId, - mContext.getPackageName()); - } - } catch (RemoteException e) { - Log.e(TAG, "Error during reset disabled apps.", e); + if (mIPm.getApplicationEnabledSetting(app.packageName, userId) + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + mIPm.setApplicationEnabledSetting(app.packageName, + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP, + userId, + mContext.getPackageName()); } + } catch (RemoteException e) { + Log.e(TAG, "Error during reset disabled apps.", e); } } } - try { - mIPm.resetApplicationPreferences(UserHandle.myUserId()); - } catch (RemoteException e) { - } - mAom.resetAllModes(); - BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom); - final int[] restrictedUids = mNpm.getUidsWithPolicy( - POLICY_REJECT_METERED_BACKGROUND); - final int currentUserId = ActivityManager.getCurrentUser(); - for (int uid : restrictedUids) { - // Only reset for current user - if (UserHandle.getUserId(uid) == currentUserId) { - mNpm.setUidPolicy(uid, POLICY_NONE); - } + } + try { + mIPm.resetApplicationPreferences(UserHandle.myUserId()); + } catch (RemoteException e) { + } + mAom.resetAllModes(); + BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom); + final int[] restrictedUids = mNpm.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND); + final int currentUserId = ActivityManager.getCurrentUser(); + for (int uid : restrictedUids) { + // Only reset for current user + if (UserHandle.getUserId(uid) == currentUserId) { + mNpm.setUidPolicy(uid, POLICY_NONE); } } }); diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt index 3331a699a4f..f5e2e978bbf 100644 --- a/src/com/android/settings/spa/app/AllAppList.kt +++ b/src/com/android/settings/spa/app/AllAppList.kt @@ -58,10 +58,12 @@ object AllAppListPageProvider : SettingsPageProvider { @Composable private fun AllAppListPage() { + val resetAppDialogPresenter = rememberResetAppDialogPresenter() AppListPage( title = stringResource(R.string.all_apps), listModel = remember { AllAppListModel() }, showInstantApps = true, + moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) } ) { itemModel -> AppListItem( itemModel = itemModel, diff --git a/src/com/android/settings/spa/app/ResetAppPreferences.kt b/src/com/android/settings/spa/app/ResetAppPreferences.kt new file mode 100644 index 00000000000..12dd7090ea1 --- /dev/null +++ b/src/com/android/settings/spa/app/ResetAppPreferences.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.app + +import android.os.UserHandle +import android.os.UserManager +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settings.applications.manageapplications.ResetAppsHelper +import com.android.settingslib.spa.widget.dialog.AlertDialogButton +import com.android.settingslib.spa.widget.dialog.AlertDialogPresenter +import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter +import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope +import com.android.settingslib.spaprivileged.model.enterprise.Restrictions +import com.android.settingslib.spaprivileged.template.scaffold.RestrictedMenuItem + +@Composable +fun MoreOptionsScope.ResetAppPreferences(onClick: () -> Unit) { + RestrictedMenuItem( + text = stringResource(R.string.reset_app_preferences), + restrictions = remember { + Restrictions( + userId = UserHandle.myUserId(), + keys = listOf(UserManager.DISALLOW_APPS_CONTROL), + ) + }, + onClick = onClick, + ) +} + +@Composable +fun rememberResetAppDialogPresenter(): AlertDialogPresenter { + val context = LocalContext.current + return rememberAlertDialogPresenter( + confirmButton = AlertDialogButton(stringResource(R.string.reset_app_preferences_button)) { + ResetAppsHelper(context).resetApps() + }, + dismissButton = AlertDialogButton(stringResource(R.string.cancel)), + title = stringResource(R.string.reset_app_preferences_title), + text = { Text(stringResource(R.string.reset_app_preferences_desc)) }, + ) +} diff --git a/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt new file mode 100644 index 00000000000..b144ad6eecf --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.app + +import android.content.Context +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Spy + +@RunWith(AndroidJUnit4::class) +class ResetAppPreferencesTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Spy + private val context: Context = ApplicationProvider.getApplicationContext() + + @Test + fun resetAppPreferences_titleIsDisplayed() { + setResetAppPreferences() + + composeTestRule.onNodeWithText(context.getString(R.string.reset_app_preferences)) + .assertIsDisplayed() + } + + private fun setResetAppPreferences() { + val fakeMoreOptionsScope = object : MoreOptionsScope { + override fun dismiss() {} + } + composeTestRule.setContent { + fakeMoreOptionsScope.ResetAppPreferences {} + } + } + + @Test + fun resetAppDialogPresenter_confirmButtonDisplayed() { + setAndOpenDialog() + + composeTestRule.onNodeWithText(context.getString(R.string.reset_app_preferences_button)) + .assertIsDisplayed() + } + + @Test + fun resetAppDialogPresenter_titleDisplayed() { + setAndOpenDialog() + + composeTestRule.onNodeWithText(context.getString(R.string.reset_app_preferences_title)) + .assertIsDisplayed() + } + + @Test + fun resetAppDialogPresenter_textDisplayed() { + setAndOpenDialog() + + composeTestRule.onNodeWithText(context.getString(R.string.reset_app_preferences_desc)) + .assertIsDisplayed() + } + + private fun setAndOpenDialog() { + composeTestRule.setContent { + val dialogPresenter = rememberResetAppDialogPresenter() + LaunchedEffect(Unit) { + dialogPresenter.open() + } + } + } +}