From b51c7a6de355cc6b85c153879a32fcc12c8169e5 Mon Sep 17 00:00:00 2001 From: Tyler Freeman Date: Tue, 20 Sep 2022 13:21:32 -0700 Subject: [PATCH 01/15] feat(non linear font scaling): support up to 200% font scaling. Test: manual Bug: b/237558231 Change-Id: Ie8d5495d467222ef5b612abdf8059a2afab2201f --- res/values/arrays.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 35d246236f7..39cdfd15955 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -105,11 +105,16 @@ 1800000 + 0.85 1.0 1.15 1.30 + 1.50 + 1.80 + 2.0 From ef5e8670a5706c7d9a03a1cf6b9a6145181860e9 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 17 Nov 2022 16:46:05 -0800 Subject: [PATCH 02/15] Rename ACTION_MEMTAG_SETTINGS Bug: 259140983 Change-Id: Ia8fd50d2c470ec44ac0aface9a80bc9ce9fc9861 --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 74cf865361e..f4e28526f4a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -347,7 +347,7 @@ android:exported="true" android:configChanges="orientation|keyboardHidden|screenSize"> - + From db6b029287f955529a4809cdc603e004dad44ce4 Mon Sep 17 00:00:00 2001 From: Tetiana Meronyk Date: Wed, 23 Nov 2022 23:41:55 +0000 Subject: [PATCH 03/15] Remove system user from displaying in Storage Settings in HSUM Bug: 259525664 Test: croot && make RunSettingsRoboTests -j40 ROBOTEST_FILTER="com.android.settings.deviceinfo.storage.NonCurrentUserControllerTest" Change-Id: I9425a9becdb89588da4a917c0ba9401d6b354238 --- .../deviceinfo/storage/NonCurrentUserController.java | 10 +++++----- .../storage/NonCurrentUserControllerTest.java | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/deviceinfo/storage/NonCurrentUserController.java b/src/com/android/settings/deviceinfo/storage/NonCurrentUserController.java index fe7fa7c5d71..b631e353ba5 100644 --- a/src/com/android/settings/deviceinfo/storage/NonCurrentUserController.java +++ b/src/com/android/settings/deviceinfo/storage/NonCurrentUserController.java @@ -64,8 +64,8 @@ public class NonCurrentUserController extends AbstractPreferenceController imple * Adds the appropriate controllers to a controller list for handling all full non current * users on a device. * - * @param context Context for initializing the preference controllers. - * @param userManager UserManagerWrapper for figuring out which controllers to add. + * @param context Context for initializing the preference controllers. + * @param userManager UserManagerWrapper for figuring out which controllers to add. */ public static List getNonCurrentUserControllers( Context context, UserManager userManager) { @@ -73,7 +73,7 @@ public class NonCurrentUserController extends AbstractPreferenceController imple List controllers = new ArrayList<>(); List infos = userManager.getUsers(); for (UserInfo info : infos) { - if (info.id == currentUserId || info.isProfile()) { + if (info.id == currentUserId || !info.isFull()) { continue; } int[] profiles = userManager.getProfileIds(info.id, false /* enabledOnly */); @@ -85,8 +85,8 @@ public class NonCurrentUserController extends AbstractPreferenceController imple /** * Constructor for a given non-current user. * - * @param context Context to initialize the underlying {@link AbstractPreferenceController}. - * @param info {@link UserInfo} for the non-current user which these controllers cover. + * @param context Context to initialize the underlying {@link AbstractPreferenceController}. + * @param info {@link UserInfo} for the non-current user which these controllers cover. * @param profiles list of IDs or user and its profiles */ @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/NonCurrentUserControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/NonCurrentUserControllerTest.java index 684128c436f..61d3bed91c7 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/NonCurrentUserControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/NonCurrentUserControllerTest.java @@ -80,7 +80,7 @@ public class NonCurrentUserControllerTest { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mPrimaryUser = new UserInfo(); - mPrimaryUser.flags = UserInfo.FLAG_PRIMARY; + mPrimaryUser.flags = UserInfo.FLAG_PRIMARY | UserInfo.FLAG_FULL; mController = new NonCurrentUserController(mContext, mPrimaryUser); ShadowActivityManager.setService(mActivityService); @@ -267,6 +267,8 @@ public class NonCurrentUserControllerTest { secondaryUser.id = 10; final UserInfo secondaryUser1 = spy(new UserInfo()); secondaryUser1.id = 11; + secondaryUser.flags = UserInfo.FLAG_FULL; + secondaryUser1.flags = UserInfo.FLAG_FULL; userInfo.add(mPrimaryUser); userInfo.add(secondaryUser); userInfo.add(secondaryUser1); From b61949c841a1bb489f1e1b94295d704fd65a1e3e Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 24 Nov 2022 19:16:55 +0000 Subject: [PATCH 04/15] Hide remove user option for main user in multi user settings Added isMain() user check in UserDetailsSettings.initialize and UserDetailsSettings.canDeleteUser to hide and restrict delete user option for main user in multi user settings. Added unit tests for the same. Bug: 260200162 Test: Manual test on headless to check remove user option is not visible for the main user. Test: Run robo tests with this command: make -j64 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.users.UserDetailsSettingsTest" Change-Id: Ia455611a3d0b1e0945f61f00658425b7bf6c2dae --- .../settings/users/UserDetailsSettings.java | 8 +++-- .../users/UserDetailsSettingsTest.java | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index dc6fbd4a50b..44b41d09c1a 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -317,8 +317,12 @@ public class UserDetailsSettings extends SettingsPreferenceFragment mRemoveUserPref.setTitle(R.string.user_remove_user); removePreference(KEY_APP_COPYING); } + + // Remove preference KEY_REMOVE_USER if DISALLOW_REMOVE_USER restriction is set + // on the current user or the user selected in user details settings is a main user. if (RestrictedLockUtilsInternal.hasBaseUserRestriction(context, - UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId())) { + UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId()) + || mUserInfo.isMain()) { removePreference(KEY_REMOVE_USER); } @@ -331,7 +335,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment @VisibleForTesting boolean canDeleteUser() { - if (!mUserManager.isAdminUser()) { + if (!mUserManager.isAdminUser() || mUserInfo.isMain()) { return false; } diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java index fad30aa01d4..ff57ebca443 100644 --- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java +++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java @@ -387,6 +387,16 @@ public class UserDetailsSettingsTest { verify(mFragment).removePreference(KEY_REMOVE_USER); } + @Test + public void initialize_onMainUser_shouldNotShowRemovePreference() { + setupSelectedMainUser(); + mUserManager.setIsAdminUser(true); + + mFragment.initialize(mActivity, mArguments); + + verify(mFragment).removePreference(KEY_REMOVE_USER); + } + @Test public void initialize_disallowRemoveUserRestriction_shouldNotShowRemovePreference() { setupSelectedUser(); @@ -571,10 +581,22 @@ public class UserDetailsSettingsTest { assertThat(result).isFalse(); } + @Test + public void canDeleteUser_onMainUser_shouldReturnFalse() { + setupSelectedMainUser(); + mUserManager.setIsAdminUser(true); + mFragment.mUserInfo = mUserInfo; + + boolean result = mFragment.canDeleteUser(); + + assertThat(result).isFalse(); + } + @Test public void canDeleteUser_adminSelectsUser_noRestrictions_shouldReturnTrue() { setupSelectedUser(); mUserManager.setIsAdminUser(true); + mFragment.mUserInfo = mUserInfo; boolean result = mFragment.canDeleteUser(); @@ -585,6 +607,7 @@ public class UserDetailsSettingsTest { public void canDeleteUser_adminSelectsUser_hasRemoveRestriction_shouldReturnFalse() { setupSelectedUser(); mUserManager.setIsAdminUser(true); + mFragment.mUserInfo = mUserInfo; ComponentName componentName = new ComponentName("test", "test"); ShadowDevicePolicyManager.getShadow().setDeviceOwnerComponentOnAnyUser(componentName); ShadowDevicePolicyManager.getShadow().setDeviceOwnerUserId(UserHandle.myUserId()); @@ -611,6 +634,15 @@ public class UserDetailsSettingsTest { mUserManager.addProfile(mUserInfo); } + private void setupSelectedMainUser() { + mArguments.putInt("user_id", 11); + mUserInfo = new UserInfo(11, "Jerry", null, + UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MAIN, + UserManager.USER_TYPE_FULL_SECONDARY); + + mUserManager.addProfile(mUserInfo); + } + private void setupSelectedGuest() { mArguments.putInt("user_id", 23); mUserInfo = new UserInfo(23, "Guest", null, From e55a53b06768958c5906ba3bbe4a61614193b78d Mon Sep 17 00:00:00 2001 From: Jackson Michael Date: Fri, 11 Nov 2022 17:22:34 +0000 Subject: [PATCH 05/15] Changing the process to create a new user Creating a method to run in background the process to create a new user, and making the user check and change the UI in the main thread. Also deleted the message of created user from the handler. Bug:246906179 Test: Manual test and unit test fixed Change-Id: Ifb3687937987f04165fd2e099d4334c7571bb034 --- .../android/settings/users/UserSettings.java | 78 +++++++------------ .../users/UserSettingsComponentTest.java | 4 +- 2 files changed, 29 insertions(+), 53 deletions(-) diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 5f9f2fe93ac..eadc5503314 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -97,6 +97,7 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -240,9 +241,6 @@ public class UserSettings extends SettingsPreferenceFragment case MESSAGE_UPDATE_LIST: updateUserList(); break; - case MESSAGE_USER_CREATED: - onUserCreated(msg.arg1); - break; case MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED: updateUserList(); if (mGuestUserAutoCreated) { @@ -624,14 +622,13 @@ public class UserSettings extends SettingsPreferenceFragment } } - private void onUserCreated(int userId) { + private void onUserCreated(UserInfo userInfo) { hideUserCreatingDialog(); // prevent crash when config changes during user creation if (getContext() == null) { return; } mAddingUser = false; - UserInfo userInfo = mUserManager.getUserInfo(userId); openUserDetails(userInfo, true); } @@ -1011,69 +1008,50 @@ public class UserSettings extends SettingsPreferenceFragment mUserCreatingDialog = new UserCreatingDialog(getActivity()); mUserCreatingDialog.show(); - ThreadUtils.postOnBackgroundThread(new AddUserNowImpl(userType, mAddingUserName)); + createUser(userType, mAddingUserName); } @VisibleForTesting - class AddUserNowImpl implements Runnable{ - int mUserType; - String mImplAddUserName; - - AddUserNowImpl(final int userType, final String addUserName) { - mUserType = userType; - mImplAddUserName = addUserName; - } - - @Override - public void run() { - runAddUser(); - Trace.endAsyncSection("UserSettings.addUserNow", 0); - } - - private void runAddUser() { + void createUser(final int userType, String userName) { + Future unusedCreateUserFuture = ThreadUtils.postOnBackgroundThread(() -> { UserInfo user; - String username; - synchronized (mUserLock) { - username = mImplAddUserName; - } - - // Could take a few seconds - if (mUserType == USER_TYPE_USER) { - user = mUserManager.createUser(username, 0); + if (userType == USER_TYPE_USER) { + user = mUserManager.createUser( + userName, + mUserManager.USER_TYPE_FULL_SECONDARY, + 0); } else { - user = mUserManager.createRestrictedProfile(username); + user = mUserManager.createRestrictedProfile(userName); } - synchronized (mUserLock) { + ThreadUtils.postOnMainThread(() -> { if (user == null) { mAddingUser = false; mPendingUserIcon = null; mPendingUserName = null; - ThreadUtils.postOnMainThread(() -> onUserCreationFailed()); + onUserCreationFailed(); return; } - Drawable newUserIcon = mPendingUserIcon; - if (newUserIcon == null) { - newUserIcon = UserIcons.getDefaultUserIcon(getResources(), user.id, false); - } - mUserManager.setUserIcon( - user.id, UserIcons.convertToBitmapAtUserIconSize( - getResources(), newUserIcon)); - - if (mUserType == USER_TYPE_USER) { - mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); - } - - mHandler.sendMessage(mHandler.obtainMessage( - MESSAGE_USER_CREATED, user.id, user.serialNumber)); + Future unusedSettingIconFuture = ThreadUtils.postOnBackgroundThread(() -> { + Drawable newUserIcon = mPendingUserIcon; + if (newUserIcon == null) { + newUserIcon = UserIcons.getDefaultUserIcon(getResources(), user.id, false); + } + mUserManager.setUserIcon( + user.id, UserIcons.convertToBitmapAtUserIconSize( + getResources(), newUserIcon)); + }); mPendingUserIcon = null; mPendingUserName = null; - } - } - }; + + onUserCreated(user); + }); + }); + } + /** * Erase the current user (guest) and switch to another user. diff --git a/tests/componenttests/src/com/android/settings/users/UserSettingsComponentTest.java b/tests/componenttests/src/com/android/settings/users/UserSettingsComponentTest.java index b0735fb726b..d8bbc3187c6 100644 --- a/tests/componenttests/src/com/android/settings/users/UserSettingsComponentTest.java +++ b/tests/componenttests/src/com/android/settings/users/UserSettingsComponentTest.java @@ -35,7 +35,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.settings.Settings; import com.android.settings.testutils.AdbUtils; import com.android.settings.testutils.UiUtils; -import com.android.settingslib.utils.ThreadUtils; import org.junit.After; import org.junit.Before; @@ -87,8 +86,7 @@ public class UserSettingsComponentTest { ((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0); UserSettings us = (UserSettings) f; Log.d(TAG, "Start to add user :" + randomUserName); - ThreadUtils.postOnBackgroundThread( - us.new AddUserNowImpl(USER_TYPE_RESTRICTED_PROFILE, randomUserName)); + us.createUser(USER_TYPE_RESTRICTED_PROFILE, randomUserName); }); assertThat( From 2cc51c1685ae0dff6a0ed142d3e32823d76df7a2 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 23 Nov 2022 15:50:30 +0800 Subject: [PATCH 06/15] Add ResetAppPreferences to AllAppListPage Fix: 259520506 Test: Unit test Test: Manually with Settings Change-Id: I3cbd1171df7e6bfcac6b9ebf4901e36fc2d7b14f --- .../manageapplications/ResetAppsHelper.java | 91 +++++++++---------- .../android/settings/spa/app/AllAppList.kt | 2 + .../settings/spa/app/ResetAppPreferences.kt | 60 ++++++++++++ .../spa/app/ResetAppPreferencesTest.kt | 90 ++++++++++++++++++ 4 files changed, 197 insertions(+), 46 deletions(-) create mode 100644 src/com/android/settings/spa/app/ResetAppPreferences.kt create mode 100644 tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt 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() + } + } + } +} From 42ee738f1b3e7d64c5724188cacbd089b59d106b Mon Sep 17 00:00:00 2001 From: DingFei Song Date: Mon, 21 Nov 2022 18:37:58 +0800 Subject: [PATCH 07/15] Only one channel is reserved for WifiP2pSettings Every time we enter WifiP2pSettings, a channel will be created, but we should keep only one channel if p2p connected. Bug: 259364357 Change-Id: Ie3c1b1281d74332cd5df720fb13476097f3f5df9 Merged-In: I999b108bc3e3c22519398a55b503078c1069cef1 Signed-off-by: DingFei Song --- .../settings/wifi/p2p/WifiP2pSettings.java | 60 +++++++++---------- .../wifi/p2p/WifiP2pSettingsTest.java | 8 +-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java index f862371c502..597d37ac685 100644 --- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java +++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java @@ -76,7 +76,7 @@ public class WifiP2pSettings extends DashboardFragment private final IntentFilter mIntentFilter = new IntentFilter(); @VisibleForTesting WifiP2pManager mWifiP2pManager; - @VisibleForTesting WifiP2pManager.Channel mChannel; + @VisibleForTesting static WifiP2pManager.Channel sChannel; @VisibleForTesting OnClickListener mRenameListener; @VisibleForTesting OnClickListener mDisconnectListener; @VisibleForTesting OnClickListener mCancelConnectListener; @@ -145,8 +145,8 @@ public class WifiP2pSettings extends DashboardFragment // Requesting our own device info as an app holding the NETWORK_SETTINGS permission // ensures that the MAC address will be available in the result. if (DBG) Log.d(TAG, "This device changed. Requesting device info."); - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this); + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this); } } else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) { int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, @@ -158,8 +158,8 @@ public class WifiP2pSettings extends DashboardFragment updateSearchMenu(false); } } else if (WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED.equals(action)) { - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this); + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.requestPersistentGroupInfo(sChannel, WifiP2pSettings.this); } } } @@ -234,7 +234,7 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - if (mWifiP2pManager != null && mChannel != null) { + if (mWifiP2pManager != null && sChannel != null) { String name = mDeviceNameText.getText().toString(); if (name != null) { for (int i = 0; i < name.length(); i++) { @@ -248,7 +248,7 @@ public class WifiP2pSettings extends DashboardFragment } } } - mWifiP2pManager.setDeviceName(mChannel, + mWifiP2pManager.setDeviceName(sChannel, mDeviceNameText.getText().toString(), new WifiP2pManager.ActionListener() { public void onSuccess() { @@ -270,8 +270,8 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() { + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.removeGroup(sChannel, new WifiP2pManager.ActionListener() { public void onSuccess() { if (DBG) Log.d(TAG, " remove group success"); } @@ -289,8 +289,8 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.cancelConnect(mChannel, + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.cancelConnect(sChannel, new WifiP2pManager.ActionListener() { public void onSuccess() { if (DBG) Log.d(TAG, " cancel connect success"); @@ -309,10 +309,10 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - if (mWifiP2pManager != null && mChannel != null) { + if (mWifiP2pManager != null && sChannel != null) { if (mSelectedGroup != null) { if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName()); - mWifiP2pManager.deletePersistentGroup(mChannel, + mWifiP2pManager.deletePersistentGroup(sChannel, mSelectedGroup.getNetworkId(), new WifiP2pManager.ActionListener() { public void onSuccess() { @@ -352,12 +352,12 @@ public class WifiP2pSettings extends DashboardFragment if (mWifiP2pManager != null && initChannel()) { // Register receiver after make sure channel exist getActivity().registerReceiver(mReceiver, mIntentFilter); - mWifiP2pManager.requestPeers(mChannel, WifiP2pSettings.this); - mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this); + mWifiP2pManager.requestPeers(sChannel, WifiP2pSettings.this); + mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this); mIsIgnoreInitConnectionInfoCallback = false; - mWifiP2pManager.requestNetworkInfo(mChannel, networkInfo -> { - if (mChannel == null) return; - mWifiP2pManager.requestConnectionInfo(mChannel, wifip2pinfo -> { + mWifiP2pManager.requestNetworkInfo(sChannel, networkInfo -> { + if (sChannel == null) return; + mWifiP2pManager.requestConnectionInfo(sChannel, wifip2pinfo -> { if (!mIsIgnoreInitConnectionInfoCallback) { if (networkInfo.isConnected()) { if (DBG) { @@ -377,8 +377,8 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onPause() { super.onPause(); - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.stopPeerDiscovery(mChannel, null); + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.stopPeerDiscovery(sChannel, null); } getActivity().unregisterReceiver(mReceiver); } @@ -386,11 +386,11 @@ public class WifiP2pSettings extends DashboardFragment @Override public void onStop() { super.onStop(); - if (mWifiP2pManager != null && mChannel != null) { + if (mWifiP2pManager != null && sChannel != null) { if (!mLastGroupFormed) { // Close the channel when p2p doesn't connected. - mChannel.close(); - mChannel = null; + sChannel.close(); + sChannel = null; } } } @@ -463,8 +463,8 @@ public class WifiP2pSettings extends DashboardFragment config.wps.setup = WpsInfo.DISPLAY; } } - if (mWifiP2pManager != null && mChannel != null) { - mWifiP2pManager.connect(mChannel, config, + if (mWifiP2pManager != null && sChannel != null) { + mWifiP2pManager.connect(sChannel, config, new WifiP2pManager.ActionListener() { public void onSuccess() { if (DBG) Log.d(TAG, " connect success"); @@ -646,8 +646,8 @@ public class WifiP2pSettings extends DashboardFragment } private void startSearch() { - if (mWifiP2pManager != null && mChannel != null && !mWifiP2pSearching) { - mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { + if (mWifiP2pManager != null && sChannel != null && !mWifiP2pSearching) { + mWifiP2pManager.discoverPeers(sChannel, new WifiP2pManager.ActionListener() { public void onSuccess() { } public void onFailure(int reason) { @@ -658,14 +658,14 @@ public class WifiP2pSettings extends DashboardFragment } private boolean initChannel() { - if (mChannel != null) { + if (sChannel != null) { return true; } if (mWifiP2pManager != null) { - mChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(), + sChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(), getActivity().getMainLooper(), null); } - if (mChannel == null) { + if (sChannel == null) { Log.e(TAG, "Failed to set up connection with wifi p2p service"); return false; } diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java index 3769f30fbee..8fb4c7f561c 100644 --- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java @@ -336,7 +336,7 @@ public class WifiP2pSettingsTest { public void onStop_notLastGroupFormed_shouldCloseChannel() { mFragment.onStop(); - assertThat(mFragment.mChannel).isNull(); + assertThat(mFragment.sChannel).isNull(); } @Test @@ -353,7 +353,7 @@ public class WifiP2pSettingsTest { verify(mWifiP2pManager, times(1)).stopPeerDiscovery(any(), any()); mFragment.onResume(); - assertThat(mFragment.mChannel).isNotNull(); + assertThat(mFragment.sChannel).isNotNull(); } @Test @@ -524,7 +524,7 @@ public class WifiP2pSettingsTest { @Test public void onCreateView_withNullP2pManager_shouldGetP2pManagerAgain() { - mFragment.mChannel = null; // Reset channel to re-test onCreateView flow + mFragment.sChannel = null; // Reset channel to re-test onCreateView flow mFragment.mWifiP2pManager = null; mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle()); @@ -535,7 +535,7 @@ public class WifiP2pSettingsTest { @Test public void onCreateView_withNullChannel_shouldSetP2pManagerNull() { doReturn(null).when(mWifiP2pManager).initialize(any(), any(), any()); - mFragment.mChannel = null; // Reset channel to re-test onCreateView flow + mFragment.sChannel = null; // Reset channel to re-test onCreateView flow mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle()); assertThat(mFragment.mWifiP2pManager).isNull(); From fbb154b1efcec8010457a84ac4856315497ddec3 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Tue, 29 Nov 2022 12:05:13 +0800 Subject: [PATCH 08/15] Add page id enum for storage settings - Add SettingsEnums.SETTINGS_STORAGE_PROFILE_SELECTOR Bug: 260051818 Test: compilation Change-Id: Ic68edc9754d6e18fb58fc5708fb4eb9c2b71ec9f --- .../profileselector/ProfileSelectStorageFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java index c99b169ea2d..5babf30c185 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java @@ -17,6 +17,7 @@ package com.android.settings.dashboard.profileselector; import android.app.Activity; +import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; import android.os.UserHandle; @@ -41,7 +42,6 @@ import com.android.settings.deviceinfo.storage.StorageEntry; import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController; import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController; import com.android.settings.deviceinfo.storage.StorageUtils; -import com.android.settingslib.core.instrumentation.Instrumentable; import java.util.ArrayList; import java.util.List; @@ -323,7 +323,7 @@ public class ProfileSelectStorageFragment extends ProfileSelectFragment { @Override public int getMetricsCategory() { - return Instrumentable.METRICS_CATEGORY_UNKNOWN; + return SettingsEnums.SETTINGS_STORAGE_PROFILE_SELECTOR; } @Override From fef9b97498b66d3e069feb2836701118bc41a63f Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 21 Nov 2022 15:04:24 +0800 Subject: [PATCH 09/15] Settings 2-pane deep link vulnerabilities Settings app must not start an deep link Activity if 1. The deep link Activity is not exported. or 2. Calling package does not have the permission to start the deep link Activity. Bug: 250589026 Test: make RunSettingsRoboTests ROBOTEST_FILTER=SettingsHomepageActivityTest Change-Id: I9a3bddfa5d9d1d2e924dd6f3e5e07dca6c11664f Merged-In: I9a3bddfa5d9d1d2e924dd6f3e5e07dca6c11664f --- .../homepage/SettingsHomepageActivity.java | 36 +++++++++++++++++++ .../SettingsHomepageActivityTest.java | 35 ++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 183a2fbf5f5..4726059455e 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -25,6 +25,8 @@ import android.app.ActivityManager; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Bundle; import android.text.TextUtils; @@ -38,6 +40,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toolbar; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -55,6 +58,7 @@ import com.android.settings.core.CategoryMixin; import com.android.settings.core.FeatureFlags; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.PasswordUtils; import com.android.settingslib.Utils; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; @@ -351,6 +355,32 @@ public class SettingsHomepageActivity extends FragmentActivity implements finish(); return; } + + if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()), + getPackageName())) { + ActivityInfo targetActivityInfo = null; + try { + targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName, + /* flags= */ 0); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to get target ActivityInfo: " + e); + finish(); + return; + } + + if (!targetActivityInfo.exported) { + Log.e(TAG, "Must not launch an unexported Actvity for deep link"); + finish(); + return; + } + + if (!isCallingAppPermitted(targetActivityInfo.permission)) { + Log.e(TAG, "Calling app must have the permission of deep link Activity"); + finish(); + return; + } + } + targetIntent.setComponent(targetComponentName); // To prevent launchDeepLinkIntentToRight again for configuration change. @@ -386,6 +416,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements startActivity(targetIntent); } + @VisibleForTesting + boolean isCallingAppPermitted(String permission) { + return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted( + this, getActivityToken(), permission); + } + private String getHighlightMenuKey() { final Intent intent = getIntent(); if (intent != null && TextUtils.equals(intent.getAction(), diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 4d203a8a6b0..4de8b005c3c 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -37,9 +39,11 @@ import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest; +import com.android.settings.testutils.shadow.ShadowPasswordUtils; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,6 +70,11 @@ public class SettingsHomepageActivityTest { MockitoAnnotations.initMocks(this); } + @After + public void tearDown() { + ShadowPasswordUtils.reset(); + } + @Test public void launch_shouldHaveAnimationForIaFragment() { final SettingsHomepageActivity activity = Robolectric.buildActivity( @@ -195,6 +204,32 @@ public class SettingsHomepageActivityTest { & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0); } + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_emptyPermission_returnTrue() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + + assertTrue(homepageActivity.isCallingAppPermitted("")); + } + + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_noGrantedPermission_returnFalse() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + + assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST")); + } + + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_grantedPermission_returnTrue() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + String permission = "android.permission.TEST"; + ShadowPasswordUtils.addGrantedPermission(permission); + + assertTrue(homepageActivity.isCallingAppPermitted(permission)); + } + @Implements(SuggestionFeatureProviderImpl.class) public static class ShadowSuggestionFeatureProviderImpl { From 0eaf7226ccf76a3866ebd5c2a6da462d2138e884 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Tue, 29 Nov 2022 16:43:36 +0800 Subject: [PATCH 10/15] Apply new metric to picture in picture detail page - Apply SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE_DETAIL Bug: 260059322 Test: make build Change-Id: I6f1cb9742ec824525460abfbc0ac23d4b50ebfd6 --- .../specialaccess/pictureinpicture/PictureInPictureDetails.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java index 3dd428b2e18..1c322ff6c49 100644 --- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java +++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java @@ -84,7 +84,7 @@ public class PictureInPictureDetails extends AppInfoWithHeader @Override public int getMetricsCategory() { - return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE; + return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE_DETAIL; } /** From e77b5bbecb7fa6919fc1ed628bcf2d049dac0240 Mon Sep 17 00:00:00 2001 From: ykhung Date: Tue, 29 Nov 2022 17:36:12 +0800 Subject: [PATCH 11/15] Replace the getBatteryLevel() method from SettingsLib API Bug: 260524172 Test: presubmit Change-Id: Icb56abd3dc258dde142a956124dc12bbfd9ae889 --- src/com/android/settings/fuelgauge/BatteryUtils.java | 9 --------- .../settings/fuelgauge/batteryusage/DatabaseUtils.java | 3 ++- .../batteryusage/BatteryUsageBroadcastReceiverTest.java | 1 + 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 19d0727c19f..8bf5e166460 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -602,15 +602,6 @@ public class BatteryUtils { /*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); } - /** Gets the battery level from the intent. */ - public static int getBatteryLevel(Intent intent) { - final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - final int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); - return scale == 0 - ? -1 /*invalid battery level*/ - : Math.round((level / (float) scale) * 100f); - } - /** Gets the current dock defender mode */ public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) { if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) { diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java index c7dbebbc701..fdcbb4a52a2 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java @@ -36,6 +36,7 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; +import com.android.settingslib.fuelgauge.BatteryStatus; import java.time.Clock; import java.time.Duration; @@ -149,7 +150,7 @@ public final class DatabaseUtils { clearMemory(); return null; } - final int batteryLevel = BatteryUtils.getBatteryLevel(intent); + final int batteryLevel = BatteryStatus.getBatteryLevel(intent); final int batteryStatus = intent.getIntExtra( BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); final int batteryHealth = intent.getIntExtra( diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java index 513dfdfed83..addfd9bfdb9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java @@ -132,6 +132,7 @@ public final class BatteryUsageBroadcastReceiverTest { private static Intent getBatteryIntent(int level, int status) { final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); intent.putExtra(BatteryManager.EXTRA_LEVEL, level); + intent.putExtra(BatteryManager.EXTRA_SCALE, 100); intent.putExtra(BatteryManager.EXTRA_STATUS, status); return intent; } From 1d0681649d084553a79b3366311f501d55669c73 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Tue, 29 Nov 2022 22:24:52 +0000 Subject: [PATCH 12/15] Add more details for translators. Bug: 245624194 Change-Id: Ib37852579124235f7fe11c108ff98569a3286536 --- res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 28378c48969..d91cb88c499 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10492,7 +10492,10 @@ Reboot with MTE System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot. + Try MTE for a single boot for app development + MTE is enabled through Advanced memory protection Capturing system heap dump From 391a34f7d53d110b7a479c116eb68f338dec0be3 Mon Sep 17 00:00:00 2001 From: Joshua Mccloskey Date: Wed, 30 Nov 2022 00:07:06 +0000 Subject: [PATCH 13/15] Revert "Fix the flicker of FingerprintSettings before FingerprintEnrollIntro." This reverts commit 3ca9965a9693894e913d4b97819b27aa0b644e21. Reason for revert: b/259709482 Change-Id: I1fcc8b3ecd42859af591a7b250edfedbbdf204e4 --- .../fingerprint/FingerprintStatusUtilsTest.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java index a5d74a03500..69e5e2f485b 100644 --- a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java +++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java @@ -179,20 +179,8 @@ public class FingerprintStatusUtilsTest { } @Test - public void getSettingsClassName_whenNotEnrolled_fingerprintOnly_returnsFingerprintEnrollInduction() { + public void getSettingsClassName_whenNotEnrolled_returnsFingerprintSettings() { when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false); - when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - when(mFaceManager.isHardwareDetected()).thenReturn(false); - - assertThat(mFingerprintStatusUtils.getSettingsClassName()) - .isEqualTo(FingerprintEnrollIntroductionInternal.class.getName()); - } - - @Test - public void getSettingsClassName_whenNotEnrolled_fingerprintNotOnly_returnsFingerprintSettings() { - when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false); - when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - when(mFaceManager.isHardwareDetected()).thenReturn(true); assertThat(mFingerprintStatusUtils.getSettingsClassName()) .isEqualTo(FingerprintSettings.class.getName()); From 4003c679f19b378aca73bbdb321b7f190ecc8cfd Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 30 Nov 2022 11:43:52 +0800 Subject: [PATCH 14/15] Fix R for BatteryInfo Bug: 260441791 Test: Make Settings Change-Id: I4d330b5724a85fdd41f4415199143b4e64589151 --- src/com/android/settings/fuelgauge/BatteryInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java index cfa537b31f5..ce441c841c9 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfo.java +++ b/src/com/android/settings/fuelgauge/BatteryInfo.java @@ -33,10 +33,10 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.internal.os.BatteryStatsHistoryIterator; +import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.UsageView; -import com.android.settingslib.R; import com.android.settingslib.fuelgauge.Estimate; import com.android.settingslib.fuelgauge.EstimateKt; import com.android.settingslib.utils.PowerUtil; From c2a42f21625775411dd7994924d1df5bebdb0ba4 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Tue, 29 Nov 2022 12:00:20 +0800 Subject: [PATCH 15/15] Update for AppListItem Bug: 260660819 Test: Manually with Settings Change-Id: I67b8ff2d8e280c18e191c63ca891a8d7d3706aed --- .../android/settings/spa/app/AllAppList.kt | 5 ++-- .../settings/spa/development/UsageStats.kt | 4 +--- .../spa/notification/AppListNotifications.kt | 17 +++++--------- .../settings/spa/system/AppLanguages.kt | 23 ++++++++----------- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt index ba7c300091b..f8c5c0f63e9 100644 --- a/src/com/android/settings/spa/app/AllAppList.kt +++ b/src/com/android/settings/spa/app/AllAppList.kt @@ -64,10 +64,9 @@ private fun AllAppListPage() { listModel = remember { AllAppListModel() }, showInstantApps = true, moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) } - ) { itemModel -> + ) { AppListItem( - itemModel = itemModel, - onClick = AppInfoSettingsProvider.navigator(app = itemModel.record.app), + onClick = AppInfoSettingsProvider.navigator(app = record.app), ) } } diff --git a/src/com/android/settings/spa/development/UsageStats.kt b/src/com/android/settings/spa/development/UsageStats.kt index 302f2010b31..d98ef599f9c 100644 --- a/src/com/android/settings/spa/development/UsageStats.kt +++ b/src/com/android/settings/spa/development/UsageStats.kt @@ -37,9 +37,7 @@ object UsageStatsPageProvider : SettingsPageProvider { title = stringResource(R.string.testing_usage_stats), listModel = rememberContext(::UsageStatsListModel), primaryUserOnly = true, - ) { itemModel -> - AppListItem(itemModel) {} - } + ) { AppListItem {} } } @Composable diff --git a/src/com/android/settings/spa/notification/AppListNotifications.kt b/src/com/android/settings/spa/notification/AppListNotifications.kt index da4ebb5dc21..0e6c5e2d6da 100644 --- a/src/com/android/settings/spa/notification/AppListNotifications.kt +++ b/src/com/android/settings/spa/notification/AppListNotifications.kt @@ -46,9 +46,7 @@ object AppListNotificationsPageProvider : SettingsPageProvider { AppListPage( title = stringResource(R.string.app_notifications_title), listModel = rememberContext(::AppNotificationsListModel), - ) { - AppNotificationsItem(it) - } + ) { AppNotificationsItem() } } @Composable @@ -62,24 +60,21 @@ object AppListNotificationsPageProvider : SettingsPageProvider { } @Composable -private fun AppNotificationsItem( - itemModel: AppListItemModel, -) { +private fun AppListItemModel.AppNotificationsItem() { val appNotificationsRepository = rememberContext(::AppNotificationRepository) val context = LocalContext.current AppListSwitchItem( - itemModel = itemModel, onClick = { navigateToAppNotificationSettings( context = context, - app = itemModel.record.app, + app = record.app, ) }, - checked = itemModel.record.controller.isEnabled.observeAsState(), + checked = record.controller.isEnabled.observeAsState(), changeable = produceState(initialValue = false) { - value = appNotificationsRepository.isChangeable(itemModel.record.app) + value = appNotificationsRepository.isChangeable(record.app) }, - onCheckedChange = itemModel.record.controller::setEnabled, + onCheckedChange = record.controller::setEnabled, ) } diff --git a/src/com/android/settings/spa/system/AppLanguages.kt b/src/com/android/settings/spa/system/AppLanguages.kt index db34cd595f1..bcb65352a27 100644 --- a/src/com/android/settings/spa/system/AppLanguages.kt +++ b/src/com/android/settings/spa/system/AppLanguages.kt @@ -52,9 +52,7 @@ object AppLanguagesPageProvider : SettingsPageProvider { SettingsBody(stringResource(R.string.desc_app_locale_selection_supported)) } }, - ) { - AppLanguageItem(it) - } + ) { AppLanguageItem() } } @Composable @@ -68,16 +66,13 @@ object AppLanguagesPageProvider : SettingsPageProvider { } @Composable -private fun AppLanguageItem(itemModel: AppListItemModel) { +private fun AppListItemModel.AppLanguageItem() { val context = LocalContext.current - AppListItem( - itemModel = itemModel, - onClick = { - val intent = Intent(context, AppLocalePickerActivity::class.java).apply { - setData(Uri.parse("package:${itemModel.record.app.packageName}")) - putExtra("uid", itemModel.record.app.uid) - } - context.startActivity(intent) + AppListItem { + val intent = Intent(context, AppLocalePickerActivity::class.java).apply { + data = Uri.parse("package:${record.app.packageName}") + putExtra("uid", record.app.uid) } - ) -} \ No newline at end of file + context.startActivity(intent) + } +}