From 54a1c53c2ae53f48fefd0b4a7ea547428d601d3b Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 13 Dec 2023 08:23:40 +0000 Subject: [PATCH 01/10] Add talkback feedback when setting passowrd/pin/pattern complete Bug: 297959385 Test: 1. Enable talkback 2. Change or Set a password/pattern/pin 3. Check if there is a feedback after setting complete Change-Id: I9a63bc99575e27b504dd3130e416f65dac068b4e --- res/values/strings.xml | 3 +++ src/com/android/settings/password/ChooseLockPassword.java | 6 ++++++ src/com/android/settings/password/ChooseLockPattern.java | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 01f25252be1..c8d2990dae4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12633,4 +12633,7 @@ + + + Password is now set up diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 800adb063cb..d36fb897ffc 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -1084,6 +1084,12 @@ public class ChooseLockPassword extends SettingsActivity { startActivity(intent); } } + + if (mLayout != null) { + mLayout.announceForAccessibility( + getString(R.string.accessibility_setup_password_complete)); + } + getActivity().finish(); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 20d1e7d8cd1..075dab183c0 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -871,6 +871,12 @@ public class ChooseLockPattern extends SettingsActivity { startActivity(intent); } } + + if (mSudContent != null) { + mSudContent.announceForAccessibility( + getString(R.string.accessibility_setup_password_complete)); + } + getActivity().finish(); } } From bb544ffef2bfc0d17cbf6ed51556715dd3f68f8c Mon Sep 17 00:00:00 2001 From: MiltonWu Date: Thu, 14 Dec 2023 06:49:16 +0000 Subject: [PATCH 02/10] Apply nosensor for face unlock enroll activities Bug: 300351527 Test: Launch related activites on a foldable device with landscape mode Change-Id: I0bcf48f09ec6177f19342bbe65fb5ea2e54a41d3 --- AndroidManifest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 19927a2ed02..e8ff440b93b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2517,7 +2517,7 @@ + android:screenOrientation="nosensor"> @@ -2526,12 +2526,12 @@ + android:screenOrientation="nosensor"/> Date: Fri, 15 Dec 2023 12:35:56 +0900 Subject: [PATCH 03/10] Prevent NetworkRequestDialogActivity recreation on some configuration change NetworkRequestDialogActivity's internal state gets reset if Configuration change happens, for example rotation or resize. This change prevents such an unwanted restart of Activity. Bug: 314893682 Test: resizing the dialog won't trigger restart. Change-Id: Ia628db81b76d8b15f2ac11f53652e444c44f564d (cherry picked from commit c53818a4569ce011820732d842eaa57ab1bcc52b) --- AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 19927a2ed02..eb52fc1b29c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3885,6 +3885,7 @@ android:launchMode="singleTop" android:taskAffinity=".wifi.NetworkRequestDialogActivity" android:exported="true" + android:configChanges="orientation|keyboard|keyboardHidden|screenSize|smallestScreenSize|screenLayout" android:permission="android.permission.NETWORK_SETTINGS"> From cd516c8d46ad16b1ad266a23321b79a039e88696 Mon Sep 17 00:00:00 2001 From: Jun Lan Date: Mon, 18 Dec 2023 17:00:39 +0800 Subject: [PATCH 04/10] Fix work profile apps are in Uninstalled Context: work profile apps needs to pass userId to packageManager to get the uid. Fixed screenshot: https://screenshot.googleplex.com/AkXfMWvmREyQJvv Bug: 315477872 Fix: 315477872 Test: manual Change-Id: I96eb42ef6ce27f15415f0e1fc32060d69b3fab2d --- .../settings/fuelgauge/BatteryUtils.java | 20 ++++++++++++++++++- .../batteryusage/BatteryDiffEntry.java | 12 +++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 5a808f2d485..f4217b6bf48 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -144,7 +144,6 @@ public class BatteryUtils { sInstance = null; } - /** Gets the process time */ public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid, int which) { if (uid == null) { @@ -344,6 +343,25 @@ public class BatteryUtils { } } + /** + * Find package uid from package name + * + * @param packageName used to find the uid + * @param userId The user handle identifier to look up the package under + * @return uid for packageName, or {@link #UID_NULL} if exception happens or {@code packageName} + * is null + */ + public int getPackageUidAsUser(String packageName, int userId) { + try { + return packageName == null + ? UID_NULL + : mPackageManager.getPackageUidAsUser( + packageName, PackageManager.GET_META_DATA, userId); + } catch (PackageManager.NameNotFoundException e) { + return UID_NULL; + } + } + /** * Parses proto object from string. * diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java index 2c376e5fcec..5b05e347fdd 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java @@ -324,7 +324,8 @@ public class BatteryDiffEntry { } } - int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName); + int uid = + BatteryUtils.getInstance(mContext).getPackageUidAsUser(packageName, (int) mUserId); synchronized (sPackageNameAndUidCacheLock) { sPackageNameAndUidCache.put(packageName, uid); } @@ -379,8 +380,7 @@ public class BatteryDiffEntry { mAppIcon = nameAndIconForUser.mIcon; mAppLabel = nameAndIconForUser.mName; putResourceCache( - getKey(), - new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0)); + getKey(), new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0)); } break; case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: @@ -392,8 +392,7 @@ public class BatteryDiffEntry { mAppIconId = nameAndIconForSystem.mIconId; mAppIcon = mContext.getDrawable(nameAndIconForSystem.mIconId); } - putResourceCache( - getKey(), new NameAndIcon(mAppLabel, mAppIcon, mAppIconId)); + putResourceCache(getKey(), new NameAndIcon(mAppLabel, mAppIcon, mAppIconId)); } break; case ConvertUtils.CONSUMER_TYPE_UID_BATTERY: @@ -406,8 +405,7 @@ public class BatteryDiffEntry { mAppIcon = getBadgeIconForUser(mAppIcon); if (mAppLabel != null || mAppIcon != null) { putResourceCache( - getKey(), - new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0)); + getKey(), new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0)); } break; } From 907b47105be2bea44ca3d67f7613e59ea87a698e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= Date: Mon, 11 Dec 2023 18:06:28 +0100 Subject: [PATCH 05/10] Tag Zen operations from Settings as coming from the user Bug: 308670715 Test: atest ApprovalPreferenceControllerTest Change-Id: Id118f867e84f3d742db6b12eab0f34df1357d178 --- .../ApprovalPreferenceController.java | 6 ++- .../zenaccess/ZenAccessController.java | 8 +++- .../DndConditionCardController.java | 8 +++- .../notification/zen/ZenModeBackend.java | 47 ++++++++++++++----- .../notification/zen/ZenModeSliceBuilder.java | 8 +++- .../zen/ZenOnboardingActivity.java | 7 ++- .../ApprovalPreferenceControllerTest.java | 12 ++++- 7 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java index fb78e3eb077..00f06258ee0 100644 --- a/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java @@ -139,7 +139,11 @@ public class ApprovalPreferenceController extends BasePreferenceController { AsyncTask.execute(() -> { if (!mNm.isNotificationPolicyAccessGrantedForPackage( cn.getPackageName())) { - mNm.removeAutomaticZenRules(cn.getPackageName()); + if (android.app.Flags.modesApi()) { + mNm.removeAutomaticZenRules(cn.getPackageName(), /* fromUser= */ true); + } else { + mNm.removeAutomaticZenRules(cn.getPackageName()); + } } }); } diff --git a/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessController.java b/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessController.java index b4a0c88d950..6f4137c224a 100644 --- a/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessController.java +++ b/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessController.java @@ -101,8 +101,12 @@ public class ZenAccessController extends BasePreferenceController { } public static void deleteRules(final Context context, final String pkg) { - final NotificationManager mgr = context.getSystemService(NotificationManager.class); - mgr.removeAutomaticZenRules(pkg); + final NotificationManager mgr = context.getSystemService(NotificationManager.class); + if (android.app.Flags.modesApi()) { + mgr.removeAutomaticZenRules(pkg, /* fromUser= */ true); + } else { + mgr.removeAutomaticZenRules(pkg); + } } @VisibleForTesting diff --git a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java index 4d79a013f7f..e69a336edd5 100644 --- a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java +++ b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java @@ -16,6 +16,7 @@ package com.android.settings.homepage.contextualcards.conditional; +import android.app.Flags; import android.app.NotificationManager; import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; @@ -86,7 +87,12 @@ public class DndConditionCardController implements ConditionalCardController { @Override public void onActionClick() { - mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG); + if (Flags.modesApi()) { + mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG, + /* fromUser= */ true); + } else { + mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG); + } } @Override diff --git a/src/com/android/settings/notification/zen/ZenModeBackend.java b/src/com/android/settings/notification/zen/ZenModeBackend.java index 10798652e68..c290c83f5d2 100644 --- a/src/com/android/settings/notification/zen/ZenModeBackend.java +++ b/src/com/android/settings/notification/zen/ZenModeBackend.java @@ -56,7 +56,6 @@ public class ZenModeBackend { @VisibleForTesting protected static final String ZEN_MODE_FROM_NONE = "zen_mode_from_none"; protected static final int SOURCE_NONE = -1; - private static List mDefaultRuleIds; private static ZenModeBackend sInstance; @@ -65,7 +64,7 @@ public class ZenModeBackend { protected NotificationManager.Policy mPolicy; private final NotificationManager mNotificationManager; - private String TAG = "ZenModeSettingsBackend"; + private static final String TAG = "ZenModeSettingsBackend"; private final Context mContext; public static ZenModeBackend getInstance(Context context) { @@ -95,19 +94,32 @@ public class ZenModeBackend { } protected boolean updateZenRule(String id, AutomaticZenRule rule) { - return NotificationManager.from(mContext).updateAutomaticZenRule(id, rule); + if (android.app.Flags.modesApi()) { + return mNotificationManager.updateAutomaticZenRule(id, rule, /* fromUser= */ true); + } else { + return NotificationManager.from(mContext).updateAutomaticZenRule(id, rule); + } } protected void setZenMode(int zenMode) { - NotificationManager.from(mContext).setZenMode(zenMode, null, TAG); + if (android.app.Flags.modesApi()) { + mNotificationManager.setZenMode(zenMode, null, TAG, /* fromUser= */ true); + } else { + NotificationManager.from(mContext).setZenMode(zenMode, null, TAG); + } mZenMode = getZenMode(); } protected void setZenModeForDuration(int minutes) { Uri conditionId = ZenModeConfig.toTimeCondition(mContext, minutes, ActivityManager.getCurrentUser(), true).id; - mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, - conditionId, TAG); + if (android.app.Flags.modesApi()) { + mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, + conditionId, TAG, /* fromUser= */ true); + } else { + mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, + conditionId, TAG); + } mZenMode = getZenMode(); } @@ -180,7 +192,11 @@ public class ZenModeBackend { int priorityConversationSenders) { mPolicy = new NotificationManager.Policy(priorityCategories, priorityCallSenders, priorityMessageSenders, suppressedVisualEffects, priorityConversationSenders); - mNotificationManager.setNotificationPolicy(mPolicy); + if (android.app.Flags.modesApi()) { + mNotificationManager.setNotificationPolicy(mPolicy, /* fromUser= */ true); + } else { + mNotificationManager.setNotificationPolicy(mPolicy); + } } @@ -357,7 +373,11 @@ public class ZenModeBackend { } public boolean removeZenRule(String ruleId) { - return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId); + if (android.app.Flags.modesApi()) { + return mNotificationManager.removeAutomaticZenRule(ruleId, /* fromUser= */ true); + } else { + return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId); + } } public NotificationManager.Policy getConsolidatedPolicy() { @@ -366,7 +386,11 @@ public class ZenModeBackend { protected String addZenRule(AutomaticZenRule rule) { try { - return NotificationManager.from(mContext).addAutomaticZenRule(rule); + if (android.app.Flags.modesApi()) { + return mNotificationManager.addAutomaticZenRule(rule, /* fromUser= */ true); + } else { + return NotificationManager.from(mContext).addAutomaticZenRule(rule); + } } catch (Exception e) { return null; } @@ -429,10 +453,7 @@ public class ZenModeBackend { } private static List getDefaultRuleIds() { - if (mDefaultRuleIds == null) { - mDefaultRuleIds = ZenModeConfig.DEFAULT_RULE_IDS; - } - return mDefaultRuleIds; + return ZenModeConfig.DEFAULT_RULE_IDS; } NotificationManager.Policy toNotificationPolicy(ZenPolicy policy) { diff --git a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java index 8082bcdc046..4f6f0587b46 100644 --- a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java +++ b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java @@ -19,6 +19,7 @@ package com.android.settings.notification.zen; import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import android.annotation.ColorInt; +import android.app.Flags; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.settings.SettingsEnums; @@ -116,7 +117,12 @@ public class ZenModeSliceBuilder { } else { zenMode = Settings.Global.ZEN_MODE_OFF; } - NotificationManager.from(context).setZenMode(zenMode, null /* conditionId */, TAG); + if (Flags.modesApi()) { + NotificationManager.from(context).setZenMode(zenMode, /* conditionId= */ null, TAG, + /* fromUser= */ true); + } else { + NotificationManager.from(context).setZenMode(zenMode, null /* conditionId */, TAG); + } // Do not notifyChange on Uri. The service takes longer to update the current value than it // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay} // handle it. diff --git a/src/com/android/settings/notification/zen/ZenOnboardingActivity.java b/src/com/android/settings/notification/zen/ZenOnboardingActivity.java index 23c388bf5cd..a6e78eb2068 100644 --- a/src/com/android/settings/notification/zen/ZenOnboardingActivity.java +++ b/src/com/android/settings/notification/zen/ZenOnboardingActivity.java @@ -17,6 +17,7 @@ package com.android.settings.notification.zen; import android.app.Activity; +import android.app.Flags; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.app.settings.SettingsEnums; @@ -129,7 +130,11 @@ public class ZenOnboardingActivity extends Activity { Policy.PRIORITY_SENDERS_STARRED, policy.priorityMessageSenders, NotificationManager.Policy.getAllSuppressedVisualEffects()); - mNm.setNotificationPolicy(newPolicy); + if (Flags.modesApi()) { + mNm.setNotificationPolicy(newPolicy, /* fromUser= */ true); + } else { + mNm.setNotificationPolicy(newPolicy); + } mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_OK); } else { mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java index 4601a1cfbaa..fa5af6d4f9e 100644 --- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -27,12 +28,15 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; +import android.app.Flags; import android.app.NotificationManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -42,6 +46,7 @@ import com.android.settings.testutils.FakeFeatureFactory; import com.android.settingslib.RestrictedSwitchPreference; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -50,6 +55,10 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class ApprovalPreferenceControllerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule( + SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT); + private Context mContext; private FakeFeatureFactory mFeatureFactory; @Mock @@ -80,7 +89,6 @@ public class ApprovalPreferenceControllerTest { mController.setNm(mNm); mController.setParent(mFragment); mController.setPkgInfo(mPkgInfo); - } @Test @@ -165,6 +173,7 @@ public class ApprovalPreferenceControllerTest { } @Test + @EnableFlags(Flags.FLAG_MODES_API) public void disable() { mController.disable(mCn); verify(mFeatureFactory.metricsFeatureProvider).action( @@ -172,6 +181,7 @@ public class ApprovalPreferenceControllerTest { MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW, "a"); + verify(mNm).removeAutomaticZenRules(eq(mCn.getPackageName()), eq(true)); verify(mNm).setNotificationListenerAccessGranted(mCn, false); } } From 223737e0b51471fb254b96e7b71395cdfc15973e Mon Sep 17 00:00:00 2001 From: josephpv Date: Mon, 11 Dec 2023 11:34:00 +0000 Subject: [PATCH 06/10] Show customized message for private space while choosing lock The change adds private profile checks in addition to the exisiting managed profile check to show customized message while choosing lock for private profile in Pattern, PIN and Password screens. Bug: 311343571 Test: Verify lock screen message for private space Change-Id: Ic8173ff8c1af23fc593390acaff4c67390f99b9c --- res/values/strings.xml | 6 ++ .../settings/password/ChooseLockPassword.java | 70 ++++++++++++++----- .../settings/password/ChooseLockPattern.java | 8 +++ .../onelock/PrivateSpaceLockController.java | 2 + 4 files changed, 70 insertions(+), 16 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 0b12142f53f..98529b861a8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1312,6 +1312,12 @@ Choose a lock for your private space You can unlock your private space using your fingerprint. For security, this option requires a backup lock. + + Set a PIN for your private space + + Set a password for your private space + + Set a pattern for your private space diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 800adb063cb..97d4d913454 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -260,7 +260,6 @@ public class ChooseLockPassword extends SettingsActivity { private LockscreenCredential mFirstPassword; private RecyclerView mPasswordRestrictionView; protected boolean mIsAlphaMode; - protected boolean mIsManagedProfile; protected FooterButton mSkipOrClearButton; private FooterButton mNextButton; private TextView mMessage; @@ -272,6 +271,14 @@ public class ChooseLockPassword extends SettingsActivity { private static final int CONFIRM_EXISTING_REQUEST = 58; static final int RESULT_FINISHED = RESULT_FIRST_USER; + /** Used to store the profile type for which pin/password is being set */ + protected enum ProfileType { + None, + Managed, + Private, + Other + }; + protected ProfileType mProfileType; /** * Keep track internally of where the user is in choosing a pattern. @@ -285,12 +292,14 @@ public class ChooseLockPassword extends SettingsActivity { R.string.lockpassword_choose_your_password_header_for_fingerprint, R.string.lockpassword_choose_your_password_header_for_face, R.string.lockpassword_choose_your_password_header_for_biometrics, + R.string.private_space_choose_your_password_header, // private space password R.string.lockpassword_choose_your_pin_header, // pin SET_WORK_PROFILE_PIN_HEADER, R.string.lockpassword_choose_your_profile_pin_header, R.string.lockpassword_choose_your_pin_header_for_fingerprint, R.string.lockpassword_choose_your_pin_header_for_face, R.string.lockpassword_choose_your_pin_header_for_biometrics, + R.string.private_space_choose_your_pin_header, // private space pin R.string.lock_settings_picker_biometrics_added_security_message, R.string.lock_settings_picker_biometrics_added_security_message, R.string.next_label), @@ -302,12 +311,14 @@ public class ChooseLockPassword extends SettingsActivity { R.string.lockpassword_confirm_your_password_header, R.string.lockpassword_confirm_your_password_header, R.string.lockpassword_confirm_your_password_header, + R.string.lockpassword_confirm_your_password_header, R.string.lockpassword_confirm_your_pin_header, REENTER_WORK_PROFILE_PIN_HEADER, R.string.lockpassword_reenter_your_profile_pin_header, R.string.lockpassword_confirm_your_pin_header, R.string.lockpassword_confirm_your_pin_header, R.string.lockpassword_confirm_your_pin_header, + R.string.lockpassword_confirm_your_pin_header, 0, 0, R.string.lockpassword_confirm_label), @@ -319,12 +330,14 @@ public class ChooseLockPassword extends SettingsActivity { R.string.lockpassword_confirm_passwords_dont_match, R.string.lockpassword_confirm_passwords_dont_match, R.string.lockpassword_confirm_passwords_dont_match, + R.string.lockpassword_confirm_passwords_dont_match, R.string.lockpassword_confirm_pins_dont_match, UNDEFINED, R.string.lockpassword_confirm_pins_dont_match, R.string.lockpassword_confirm_pins_dont_match, R.string.lockpassword_confirm_pins_dont_match, R.string.lockpassword_confirm_pins_dont_match, + R.string.lockpassword_confirm_pins_dont_match, 0, 0, R.string.lockpassword_confirm_label); @@ -335,29 +348,33 @@ public class ChooseLockPassword extends SettingsActivity { int hintInAlphaForFingerprint, int hintInAlphaForFace, int hintInAlphaForBiometrics, + int hintInAlphaForPrivateProfile, int hintInNumeric, String hintOverrideInNumericForProfile, int hintInNumericForProfile, int hintInNumericForFingerprint, int hintInNumericForFace, int hintInNumericForBiometrics, + int hintInNumericForPrivateProfile, int messageInAlphaForBiometrics, int messageInNumericForBiometrics, int nextButtonText) { this.alphaHint = hintInAlpha; this.alphaHintOverrideForProfile = hintOverrideInAlphaForProfile; - this.alphaHintForProfile = hintInAlphaForProfile; + this.alphaHintForManagedProfile = hintInAlphaForProfile; this.alphaHintForFingerprint = hintInAlphaForFingerprint; this.alphaHintForFace = hintInAlphaForFace; this.alphaHintForBiometrics = hintInAlphaForBiometrics; + this.alphaHintForPrivateProfile = hintInAlphaForPrivateProfile; this.numericHint = hintInNumeric; this.numericHintOverrideForProfile = hintOverrideInNumericForProfile; - this.numericHintForProfile = hintInNumericForProfile; + this.numericHintForManagedProfile = hintInNumericForProfile; this.numericHintForFingerprint = hintInNumericForFingerprint; this.numericHintForFace = hintInNumericForFace; this.numericHintForBiometrics = hintInNumericForBiometrics; + this.numericHintForPrivateProfile = hintInNumericForPrivateProfile; this.alphaMessageForBiometrics = messageInAlphaForBiometrics; this.numericMessageForBiometrics = messageInNumericForBiometrics; @@ -372,16 +389,18 @@ public class ChooseLockPassword extends SettingsActivity { // Password header public final int alphaHint; + public final int alphaHintForPrivateProfile; public final String alphaHintOverrideForProfile; - public final int alphaHintForProfile; + public final int alphaHintForManagedProfile; public final int alphaHintForFingerprint; public final int alphaHintForFace; public final int alphaHintForBiometrics; // PIN header public final int numericHint; + public final int numericHintForPrivateProfile; public final String numericHintOverrideForProfile; - public final int numericHintForProfile; + public final int numericHintForManagedProfile; public final int numericHintForFingerprint; public final int numericHintForFace; public final int numericHintForBiometrics; @@ -394,34 +413,40 @@ public class ChooseLockPassword extends SettingsActivity { public final int buttonText; - public String getHint(Context context, boolean isAlpha, int type, boolean isProfile) { + public String getHint(Context context, boolean isAlpha, int type, ProfileType profile) { if (isAlpha) { - if (type == TYPE_FINGERPRINT) { + if (android.os.Flags.allowPrivateProfile() + && profile.equals(ProfileType.Private)) { + return context.getString(alphaHintForPrivateProfile); + } else if (type == TYPE_FINGERPRINT) { return context.getString(alphaHintForFingerprint); } else if (type == TYPE_FACE) { return context.getString(alphaHintForFace); } else if (type == TYPE_BIOMETRIC) { return context.getString(alphaHintForBiometrics); - } else if (isProfile) { + } else if (profile.equals(ProfileType.Managed)) { return context.getSystemService(DevicePolicyManager.class).getResources() .getString(alphaHintOverrideForProfile, - () -> context.getString(alphaHintForProfile)); + () -> context.getString(alphaHintForManagedProfile)); } else { return context.getString(alphaHint); } } else { - if (type == TYPE_FINGERPRINT) { + if (android.os.Flags.allowPrivateProfile() + && profile.equals(ProfileType.Private)) { + return context.getString(numericHintForPrivateProfile); + } else if (type == TYPE_FINGERPRINT) { return context.getString(numericHintForFingerprint); } else if (type == TYPE_FACE) { return context.getString(numericHintForFace); } else if (type == TYPE_BIOMETRIC) { return context.getString(numericHintForBiometrics); - } else if (isProfile) { + } else if (profile.equals(ProfileType.Managed)) { return context.getSystemService(DevicePolicyManager.class).getResources() .getString(numericHintOverrideForProfile, - () -> context.getString(numericHintForProfile)); + () -> context.getString(numericHintForManagedProfile)); } else { - return context.getString(numericHint); + return context.getString(numericHint); } } } @@ -455,7 +480,7 @@ public class ChooseLockPassword extends SettingsActivity { } // Only take this argument into account if it belongs to the current profile. mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); - mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId); + mProfileType = getProfileType(); mForFingerprint = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); @@ -602,7 +627,7 @@ public class ChooseLockPassword extends SettingsActivity { if (activity instanceof SettingsActivity) { final SettingsActivity sa = (SettingsActivity) activity; String title = Stage.Introduction.getHint( - getContext(), mIsAlphaMode, getStageType(), mIsManagedProfile); + getContext(), mIsAlphaMode, getStageType(), mProfileType); sa.setTitle(title); mLayout.setHeaderText(title); } @@ -938,7 +963,7 @@ public class ChooseLockPassword extends SettingsActivity { // Hide password requirement view when we are just asking user to confirm the pw. mPasswordRestrictionView.setVisibility(View.GONE); setHeaderText(mUiStage.getHint(getContext(), mIsAlphaMode, getStageType(), - mIsManagedProfile)); + mProfileType)); setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE); mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0)); @@ -1110,5 +1135,18 @@ public class ChooseLockPassword extends SettingsActivity { } } } + + private ProfileType getProfileType() { + UserManager userManager = getContext().createContextAsUser(UserHandle.of(mUserId), + /*flags=*/0).getSystemService(UserManager.class); + if (userManager.isManagedProfile()) { + return ProfileType.Managed; + } else if (android.os.Flags.allowPrivateProfile() && userManager.isPrivateProfile()) { + return ProfileType.Private; + } else if (userManager.isProfile()) { + return ProfileType.Other; + } + return ProfileType.None; + } } } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 20d1e7d8cd1..e8595af8eb6 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -478,6 +478,8 @@ public class ChooseLockPattern extends SettingsActivity { .getString(SET_WORK_PROFILE_PATTERN_HEADER, () -> getString( R.string.lockpassword_choose_your_profile_pattern_header)); + } else if (android.os.Flags.allowPrivateProfile() && isPrivateProfile()) { + msg = getString(R.string.private_space_choose_your_pattern_header); } else { msg = getString(R.string.lockpassword_choose_your_pattern_header); } @@ -873,5 +875,11 @@ public class ChooseLockPattern extends SettingsActivity { } getActivity().finish(); } + + private boolean isPrivateProfile() { + UserManager userManager = getContext().createContextAsUser(UserHandle.of(mUserId), + /*flags=*/0).getSystemService(UserManager.class); + return userManager.isPrivateProfile(); + } } } diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java index 20298a1c003..efbe9f9200d 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java @@ -20,6 +20,7 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHOOSE_LOCK_SCREEN_TITLE; import android.content.Context; import android.content.Intent; @@ -94,6 +95,7 @@ public class PrivateSpaceLockController extends AbstractPreferenceController { final Bundle extras = new Bundle(); extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); extras.putBoolean(HIDE_INSECURE_OPTIONS, true); + extras.putInt(EXTRA_KEY_CHOOSE_LOCK_SCREEN_TITLE, R.string.private_space_lock_setup_title); new SubSettingLauncher(mContext) .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) .setSourceMetricsCategory(mHost.getMetricsCategory()) From 83c46eb1b6cebf7acefbb94dda4f2c0934aac517 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Tue, 19 Dec 2023 12:32:09 +0800 Subject: [PATCH 07/10] Fix DataUsageListTest Using androidx.fragment.app.testing.launchFragment to rewrite the test. Bug: 315449973 Test: manual - on DataUsageList Test: unit test Change-Id: Ief373becb4ac8ab1ba93b8ff3c594b5682c4821e --- .../settings/datausage/DataUsageList.kt | 55 +++--- .../settings/datausage/DataUsageListTest.kt | 168 ------------------ tests/spa_unit/Android.bp | 1 + .../settings/datausage/DataUsageListTest.kt | 131 ++++++++++++++ 4 files changed, 156 insertions(+), 199 deletions(-) delete mode 100644 tests/robotests/src/com/android/settings/datausage/DataUsageListTest.kt create mode 100644 tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt diff --git a/src/com/android/settings/datausage/DataUsageList.kt b/src/com/android/settings/datausage/DataUsageList.kt index 6a187d8caf8..3083fb75443 100644 --- a/src/com/android/settings/datausage/DataUsageList.kt +++ b/src/com/android/settings/datausage/DataUsageList.kt @@ -30,6 +30,7 @@ import androidx.annotation.VisibleForTesting import androidx.fragment.app.viewModels import androidx.preference.Preference import com.android.settings.R +import com.android.settings.dashboard.DashboardFragment import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.datausage.lib.NetworkUsageData import com.android.settings.network.MobileNetworkRepository @@ -45,43 +46,42 @@ import kotlin.jvm.optionals.getOrNull * to inspect based on usage cycle and control through [NetworkPolicy]. */ @OpenForTesting -open class DataUsageList : DataUsageBaseFragment() { - @JvmField +open class DataUsageList : DashboardFragment() { @VisibleForTesting var template: NetworkTemplate? = null + private set - @JvmField @VisibleForTesting var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID + private set - private lateinit var usageAmount: Preference - private var subscriptionInfoEntity: SubscriptionInfoEntity? = null - private lateinit var dataUsageListAppsController: DataUsageListAppsController - private lateinit var chartDataUsagePreferenceController: ChartDataUsagePreferenceController private lateinit var billingCycleRepository: BillingCycleRepository - private val viewModel: DataUsageListViewModel by viewModels() + private var usageAmount: Preference? = null + private var subscriptionInfoEntity: SubscriptionInfoEntity? = null + private var dataUsageListAppsController: DataUsageListAppsController? = null + private var chartDataUsagePreferenceController: ChartDataUsagePreferenceController? = null + private var dataUsageListHeaderController: DataUsageListHeaderController? = null - @VisibleForTesting - var dataUsageListHeaderController: DataUsageListHeaderController? = null + private val viewModel: DataUsageListViewModel by viewModels() override fun getMetricsCategory() = SettingsEnums.DATA_USAGE_LIST override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + billingCycleRepository = BillingCycleRepository(requireContext()) if (requireContext().userManager.isGuestUser) { Log.e(TAG, "This setting isn't available for guest user") EventLog.writeEvent(0x534e4554, "262741858", -1 /* UID */, "Guest user") finish() return } - billingCycleRepository = createBillingCycleRepository() if (!billingCycleRepository.isBandwidthControlEnabled()) { Log.w(TAG, "No bandwidth control; leaving") finish() return } - usageAmount = findPreference(KEY_USAGE_AMOUNT)!! + usageAmount = findPreference(KEY_USAGE_AMOUNT) processArgument() val template = template if (template == null) { @@ -94,12 +94,9 @@ open class DataUsageList : DataUsageBaseFragment() { init(template) } chartDataUsagePreferenceController = use(ChartDataUsagePreferenceController::class.java) - chartDataUsagePreferenceController.init(template) + .apply { init(template) } } - @VisibleForTesting - open fun createBillingCycleRepository() = BillingCycleRepository(requireContext()) - override fun onViewCreated(v: View, savedInstanceState: Bundle?) { super.onViewCreated(v, savedInstanceState) @@ -117,10 +114,10 @@ open class DataUsageList : DataUsageBaseFragment() { ::updateSelectedCycle, ) viewModel.cyclesFlow.collectLatestWithLifecycle(viewLifecycleOwner) { cycles -> - dataUsageListAppsController.updateCycles(cycles) + dataUsageListAppsController?.updateCycles(cycles) } viewModel.chartDataFlow.collectLatestWithLifecycle(viewLifecycleOwner) { chartData -> - chartDataUsagePreferenceController.update(chartData) + chartDataUsagePreferenceController?.update(chartData) } } @@ -128,7 +125,7 @@ open class DataUsageList : DataUsageBaseFragment() { override fun getLogTag() = TAG - fun processArgument() { + private fun processArgument() { arguments?.let { subId = it.getInt(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID) template = it.getParcelable(EXTRA_NETWORK_TEMPLATE, NetworkTemplate::class.java) @@ -145,8 +142,7 @@ open class DataUsageList : DataUsageBaseFragment() { } } - @VisibleForTesting - open fun updateSubscriptionInfoEntity() { + private fun updateSubscriptionInfoEntity() { ThreadUtils.postOnBackgroundThread { subscriptionInfoEntity = MobileNetworkRepository.getInstance(context).getSubInfoById(subId.toString()) @@ -154,19 +150,16 @@ open class DataUsageList : DataUsageBaseFragment() { } /** Update chart sweeps and cycle list to reflect [NetworkPolicy] for current [template]. */ - @VisibleForTesting - fun updatePolicy() { + private fun updatePolicy() { val isBillingCycleModifiable = isBillingCycleModifiable() dataUsageListHeaderController?.setConfigButtonVisible(isBillingCycleModifiable) - chartDataUsagePreferenceController.setBillingCycleModifiable(isBillingCycleModifiable) + chartDataUsagePreferenceController?.setBillingCycleModifiable(isBillingCycleModifiable) } - @VisibleForTesting - open fun isBillingCycleModifiable(): Boolean { - return (billingCycleRepository.isModifiable(subId) && + private fun isBillingCycleModifiable(): Boolean = + billingCycleRepository.isModifiable(subId) && requireContext().getSystemService(SubscriptionManager::class.java)!! - .getActiveSubscriptionInfo(subId) != null) - } + .getActiveSubscriptionInfo(subId) != null /** * Updates the chart and detail data when initial loaded or selected cycle changed. @@ -174,7 +167,7 @@ open class DataUsageList : DataUsageBaseFragment() { private fun updateSelectedCycle(usageData: NetworkUsageData) { Log.d(TAG, "showing cycle $usageData") - usageAmount.title = usageData.getDataUsedString(requireContext()) + usageAmount?.title = usageData.getDataUsedString(requireContext()) viewModel.selectedCycleFlow.value = usageData updateApps(usageData) @@ -182,7 +175,7 @@ open class DataUsageList : DataUsageBaseFragment() { /** Updates applications data usage. */ private fun updateApps(usageData: NetworkUsageData) { - dataUsageListAppsController.update( + dataUsageListAppsController?.update( carrierId = subscriptionInfoEntity?.carrierId, startTime = usageData.startTime, endTime = usageData.endTime, diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.kt b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.kt deleted file mode 100644 index 39b844680d2..00000000000 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.kt +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2023 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.datausage - -import android.content.Context -import android.content.Intent -import android.net.NetworkTemplate -import android.os.Bundle -import android.os.UserManager -import android.provider.Settings -import androidx.preference.Preference -import androidx.test.core.app.ApplicationProvider -import com.android.settings.datausage.DataUsageListTest.ShadowDataUsageBaseFragment -import com.android.settings.datausage.TemplatePreference.NetworkServices -import com.android.settings.datausage.lib.BillingCycleRepository -import com.android.settings.testutils.FakeFeatureFactory -import com.android.settingslib.NetworkPolicyEditor -import com.android.settingslib.core.AbstractPreferenceController -import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito.doNothing -import org.mockito.Mockito.doReturn -import org.mockito.Mockito.mock -import org.mockito.Mockito.never -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` -import org.mockito.Spy -import org.mockito.junit.MockitoJUnit -import org.mockito.junit.MockitoRule -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import org.robolectric.annotation.Implementation -import org.robolectric.annotation.Implements -import org.robolectric.util.ReflectionHelpers - -@RunWith(RobolectricTestRunner::class) -@Config(shadows = [ShadowDataUsageBaseFragment::class]) -class DataUsageListTest { - @get:Rule - val mockito: MockitoRule = MockitoJUnit.rule() - - @Mock - private lateinit var networkServices: NetworkServices - - @Mock - private lateinit var userManager: UserManager - - @Mock - private lateinit var billingCycleRepository: BillingCycleRepository - - @Mock - private lateinit var dataUsageListHeaderController: DataUsageListHeaderController - - @Spy - private val context: Context = ApplicationProvider.getApplicationContext() - - @Spy - private val dataUsageList = TestDataUsageList() - - @Before - fun setUp() { - FakeFeatureFactory.setupForTest() - networkServices.mPolicyEditor = mock(NetworkPolicyEditor::class.java) - doReturn(context).`when`(dataUsageList).context - doReturn(userManager).`when`(context).getSystemService(UserManager::class.java) - doReturn(false).`when`(userManager).isGuestUser - ReflectionHelpers.setField(dataUsageList, "services", networkServices) - doNothing().`when`(dataUsageList).updateSubscriptionInfoEntity() - `when`(billingCycleRepository.isBandwidthControlEnabled()).thenReturn(true) - dataUsageList.dataUsageListHeaderController = dataUsageListHeaderController - } - - @Test - fun onCreate_isNotGuestUser_shouldNotFinish() { - dataUsageList.template = mock(NetworkTemplate::class.java) - doReturn(false).`when`(userManager).isGuestUser - doNothing().`when`(dataUsageList).processArgument() - dataUsageList.onCreate(null) - verify(dataUsageList, never()).finish() - } - - @Test - fun onCreate_isGuestUser_shouldFinish() { - doReturn(true).`when`(userManager).isGuestUser - dataUsageList.onCreate(null) - verify(dataUsageList).finish() - } - - @Test - fun processArgument_shouldGetTemplateFromArgument() { - val args = Bundle() - args.putParcelable( - DataUsageList.EXTRA_NETWORK_TEMPLATE, mock( - NetworkTemplate::class.java - ) - ) - args.putInt(DataUsageList.EXTRA_SUB_ID, 3) - dataUsageList.arguments = args - dataUsageList.processArgument() - assertThat(dataUsageList.template).isNotNull() - assertThat(dataUsageList.subId).isEqualTo(3) - } - - @Test - fun processArgument_fromIntent_shouldGetTemplateFromIntent() { - val intent = Intent() - intent.putExtra( - Settings.EXTRA_NETWORK_TEMPLATE, mock( - NetworkTemplate::class.java - ) - ) - intent.putExtra(Settings.EXTRA_SUB_ID, 3) - doReturn(intent).`when`(dataUsageList).intent - dataUsageList.processArgument() - assertThat(dataUsageList.template).isNotNull() - assertThat(dataUsageList.subId).isEqualTo(3) - } - - @Test - fun updatePolicy_setConfigButtonVisible() { - dataUsageList.template = mock(NetworkTemplate::class.java) - dataUsageList.onCreate(null) - - dataUsageList.updatePolicy() - - verify(dataUsageListHeaderController).setConfigButtonVisible(true) - } - - @Implements(DataUsageBaseFragment::class) - class ShadowDataUsageBaseFragment { - @Implementation - fun onCreate(@Suppress("UNUSED_PARAMETER") icicle: Bundle?) { - // do nothing - } - } - - open inner class TestDataUsageList : DataUsageList() { - override fun use(clazz: Class): T = mock(clazz) - - @Suppress("UNCHECKED_CAST") - override fun findPreference(key: CharSequence): T = - mock(Preference::class.java) as T - - public override fun getIntent() = Intent() - - override fun createBillingCycleRepository() = billingCycleRepository - - override fun isBillingCycleModifiable() = true - } -} diff --git a/tests/spa_unit/Android.bp b/tests/spa_unit/Android.bp index c3e99f75dcf..4df625420eb 100644 --- a/tests/spa_unit/Android.bp +++ b/tests/spa_unit/Android.bp @@ -34,6 +34,7 @@ android_test { "androidx.compose.runtime_runtime", "androidx.test.ext.junit", "androidx.test.runner", + "androidx.fragment_fragment-testing", "flag-junit", "mockito-target-extended-minus-junit4", ], diff --git a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt new file mode 100644 index 00000000000..29ec0eed352 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2023 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.datausage + +import android.content.Context +import android.content.Intent +import android.net.NetworkTemplate +import android.os.UserManager +import android.provider.Settings +import android.telephony.SubscriptionManager +import androidx.core.os.bundleOf +import androidx.fragment.app.testing.launchFragment +import androidx.fragment.app.testing.withFragment +import androidx.lifecycle.Lifecycle +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spaprivileged.framework.common.userManager +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.stub + +private val mockUserManager: UserManager = mock() + +private val mockContext: Context = spy(ApplicationProvider.getApplicationContext()) { + on { userManager } doReturn mockUserManager +} + +private var fakeIntent = Intent() + +@RunWith(AndroidJUnit4::class) +class DataUsageListTest { + + @Before + fun setUp() { + mockUserManager.stub { + on { isGuestUser } doReturn false + } + fakeIntent = Intent() + } + + @Test + fun launchFragment_withoutArguments_finish() { + val scenario = launchFragment(initialState = Lifecycle.State.CREATED) + + scenario.withFragment { + assertThat(template).isNull() + assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + assertThat(activity!!.isFinishing).isTrue() + } + } + + @Test + fun launchFragment_isGuestUser_finish() { + mockUserManager.stub { + on { isGuestUser } doReturn true + } + val fragmentArgs = bundleOf( + DataUsageList.EXTRA_NETWORK_TEMPLATE to mock(), + DataUsageList.EXTRA_SUB_ID to 3, + ) + + val scenario = launchFragment( + fragmentArgs = fragmentArgs, + initialState = Lifecycle.State.CREATED, + ) + + scenario.withFragment { + assertThat(activity!!.isFinishing).isTrue() + } + } + + @Test + fun launchFragment_withArguments_getTemplateFromArgument() { + val fragmentArgs = bundleOf( + DataUsageList.EXTRA_NETWORK_TEMPLATE to mock(), + DataUsageList.EXTRA_SUB_ID to 3, + ) + + val scenario = launchFragment( + fragmentArgs = fragmentArgs, + initialState = Lifecycle.State.CREATED, + ) + + scenario.withFragment { + assertThat(template).isNotNull() + assertThat(subId).isEqualTo(3) + assertThat(activity!!.isFinishing).isFalse() + } + } + + @Test + fun launchFragment_withIntent_getTemplateFromIntent() { + fakeIntent = Intent().apply { + putExtra(Settings.EXTRA_NETWORK_TEMPLATE, mock()) + putExtra(Settings.EXTRA_SUB_ID, 2) + } + + val scenario = launchFragment(initialState = Lifecycle.State.CREATED) + + scenario.withFragment { + assertThat(template).isNotNull() + assertThat(subId).isEqualTo(2) + assertThat(activity!!.isFinishing).isFalse() + } + } +} + +class TestDataUsageList : DataUsageList() { + override fun getContext() = mockContext + + override fun getIntent() = fakeIntent +} From 5446813ac58eb28f907495782f540f4091a5153a Mon Sep 17 00:00:00 2001 From: shaoweishen Date: Wed, 13 Dec 2023 08:56:32 +0000 Subject: [PATCH 08/10] [PK Setting] Refine layout for Keyboard review 1. add background for keyboard review 2. add text for showing selected keyboard's name Test: Verified on device Bug: 305588594 Change-Id: Icf0f2b7798cc5cbddefc1b3a95480b48271b276f --- .../keyboard_review_layout_background.xml | 22 ++++++++++++++++ res/layout/keyboard_layout_picker.xml | 26 ++++++++++++++++--- res/values-land/dimens.xml | 3 +++ res/values/dimens.xml | 7 +++++ .../NewKeyboardLayoutPickerFragment.java | 25 +++++++++++++++++- 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 res/drawable/keyboard_review_layout_background.xml diff --git a/res/drawable/keyboard_review_layout_background.xml b/res/drawable/keyboard_review_layout_background.xml new file mode 100644 index 00000000000..7f93f80b57a --- /dev/null +++ b/res/drawable/keyboard_review_layout_background.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/res/layout/keyboard_layout_picker.xml b/res/layout/keyboard_layout_picker.xml index b25c228bf34..5e62a2c0412 100644 --- a/res/layout/keyboard_layout_picker.xml +++ b/res/layout/keyboard_layout_picker.xml @@ -17,15 +17,33 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/keyboard_picker_margin" android:id="@+id/keyboard_layout_picker_container" android:orientation="vertical"> - + android:background="@drawable/keyboard_review_layout_background"> + + + 24dp 24dp + + + 106dp diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 6c03955c1e4..3e0b8d93381 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -165,6 +165,13 @@ 1.0 0dp + + 68dp + 24dp + 16dp + 28dp + 16sp + 40dp 14sp diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java index f583971cf67..85ba5fb3270 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java @@ -26,10 +26,14 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; import androidx.fragment.app.Fragment; +import com.android.hardware.input.Flags; import com.android.settings.R; //TODO: b/316243168 - [Physical Keyboard Setting] Refactor NewKeyboardLayoutPickerFragment @@ -38,19 +42,25 @@ public class NewKeyboardLayoutPickerFragment extends Fragment { private static final int DEFAULT_KEYBOARD_PREVIEW_HEIGHT = 540; private ImageView mKeyboardLayoutPreview; + private TextView mKeyboardLayoutPreviewText; private InputManager mInputManager; private final NewKeyboardLayoutPickerController.KeyboardLayoutSelectedCallback mKeyboardLayoutSelectedCallback = new NewKeyboardLayoutPickerController.KeyboardLayoutSelectedCallback() { @Override public void onSelected(KeyboardLayout keyboardLayout) { - if (mInputManager != null && mKeyboardLayoutPreview != null) { + if (mInputManager != null + && mKeyboardLayoutPreview != null + && mKeyboardLayoutPreviewText != null && keyboardLayout != null) { Drawable previewDrawable = mInputManager.getKeyboardLayoutPreview( keyboardLayout, DEFAULT_KEYBOARD_PREVIEW_WIDTH, DEFAULT_KEYBOARD_PREVIEW_HEIGHT); mKeyboardLayoutPreview.setVisibility( previewDrawable == null ? GONE : VISIBLE); + mKeyboardLayoutPreviewText.setVisibility( + previewDrawable == null ? GONE : VISIBLE); if (previewDrawable != null) { + mKeyboardLayoutPreviewText.setText(keyboardLayout.getLabel()); mKeyboardLayoutPreview.setImageDrawable(previewDrawable); } } @@ -73,6 +83,10 @@ public class NewKeyboardLayoutPickerFragment extends Fragment { ViewGroup fragmentView = (ViewGroup) inflater.inflate( R.layout.keyboard_layout_picker, container, false); mKeyboardLayoutPreview = fragmentView.findViewById(R.id.keyboard_layout_preview); + mKeyboardLayoutPreviewText = fragmentView.findViewById(R.id.keyboard_layout_preview_name); + if (!Flags.keyboardLayoutPreviewFlag()) { + updateViewMarginForPreviewFlagOff(fragmentView); + } getActivity().getSupportFragmentManager() .beginTransaction() .replace(R.id.keyboard_layout_title, new NewKeyboardLayoutPickerTitle()) @@ -87,4 +101,13 @@ public class NewKeyboardLayoutPickerFragment extends Fragment { .commit(); return fragmentView; } + + private void updateViewMarginForPreviewFlagOff(ViewGroup fragmentView) { + LinearLayout previewContainer = fragmentView.findViewById( + R.id.keyboard_layout_picker_container); + FrameLayout.LayoutParams previewContainerLayoutParams = + (FrameLayout.LayoutParams) previewContainer.getLayoutParams(); + previewContainerLayoutParams.setMargins(0, 0, 0, 0); + previewContainer.setLayoutParams(previewContainerLayoutParams); + } } From 25ce6462c99badaa1bd538ab303549cb788bdc7e Mon Sep 17 00:00:00 2001 From: josephpv Date: Tue, 19 Dec 2023 11:01:41 +0000 Subject: [PATCH 09/10] Update strings in PS entrypoint summary and auto advance screen go/ss/B6UTjGhqwJkwGan.png go/ss/7vniU5Q5Vz3ZEEx.png Bug: 311343086, 316839546 Test: Verifed updated strings are shown Change-Id: I7b1cf54f52c0e4a1480ed95924ee28e05a2fdaf3 --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 0b12142f53f..3c5875ef86c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1207,7 +1207,7 @@ Private Space - Hide apps in a private folder + Keep private apps locked and hidden Hide apps in a private folder that only you can access @@ -1281,7 +1281,7 @@ Notifications from apps in private space are hidden when it\u2019s locked - Unlock your space to share photos or files from private space apps + Unlock private space to share photos or files from private space apps Some apps are already installed in your private space From 4c055dd097d423c0010517506b00e07b01c17d8a Mon Sep 17 00:00:00 2001 From: josephpv Date: Tue, 19 Dec 2023 11:32:11 +0000 Subject: [PATCH 10/10] Finish PS sub-settings page if PS is locked Bug: 317026141 Test: Manual Change-Id: If3a3045c40dd61779b272589231d395ce7ae9fa9 --- .../settings/privatespace/HidePrivateSpaceSettings.java | 8 ++++++++ .../privatespace/onelock/UseOneLockSettingsFragment.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java b/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java index 8c733646daa..09a1855134a 100644 --- a/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java +++ b/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java @@ -32,6 +32,14 @@ public class HidePrivateSpaceSettings extends DashboardFragment{ } } + @Override + public void onStart() { + super.onStart(); + if (PrivateSpaceMaintainer.getInstance(getContext()).isPrivateSpaceLocked()) { + finish(); + } + } + @Override public int getMetricsCategory() { return SettingsEnums.PRIVATE_SPACE_SETTINGS; diff --git a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java index 459116ace02..181a8d0ea44 100644 --- a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java +++ b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java @@ -25,6 +25,7 @@ import androidx.annotation.Nullable; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.privatespace.PrivateSpaceMaintainer; import com.android.settingslib.core.AbstractPreferenceController; import java.util.ArrayList; @@ -42,6 +43,14 @@ public class UseOneLockSettingsFragment extends DashboardFragment { } } + @Override + public void onStart() { + super.onStart(); + if (PrivateSpaceMaintainer.getInstance(getContext()).isPrivateSpaceLocked()) { + finish(); + } + } + @Override public int getMetricsCategory() { return SettingsEnums.PRIVATE_SPACE_SETTINGS;