diff --git a/res/drawable/ic_check_circle_filled_24dp.xml b/res/drawable/ic_check_circle_filled_24dp.xml
index 9d2e296ef2f..507bf678ae2 100644
--- a/res/drawable/ic_check_circle_filled_24dp.xml
+++ b/res/drawable/ic_check_circle_filled_24dp.xml
@@ -20,7 +20,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?androidprv:attr/materialColorPrimaryContainer">
+ android:tint="?android:attr/colorPrimary">
diff --git a/res/layout-land/udfps_enroll_enrolling.xml b/res/layout-land/udfps_enroll_enrolling.xml
index f3237887e9a..743684fb02e 100644
--- a/res/layout-land/udfps_enroll_enrolling.xml
+++ b/res/layout-land/udfps_enroll_enrolling.xml
@@ -96,4 +96,6 @@
+
+
\ No newline at end of file
diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml
index c97591d6d52..05556ffe46c 100644
--- a/res/layout/udfps_enroll_enrolling.xml
+++ b/res/layout/udfps_enroll_enrolling.xml
@@ -18,6 +18,7 @@
+ android:layout_gravity="center_horizontal|bottom"
+ tools:ignore="Suspicious0dp">
+
+
+
For all available hearing devices
- Shortcuts & hearing aid compatibility
+ Hearing device settings
+
+ Audio output, shortcut, hearing aid compatibility
For this device
@@ -1182,20 +1184,20 @@
Current screen lock
- Fingerprint + Pattern
+ Pattern \u2022 Fingerprint
- Fingerprint + PIN
+ PIN \u2022 Fingerprint
- Fingerprint + Password
+ Password \u2022 Fingerprint
Continue without fingerprint
- Face Unlock + Pattern
+ Pattern \u2022 Face
- Face Unlock + PIN
+ PIN \u2022 Face
- Face Unlock + Password
+ Password \u2022 Face
Continue without Face Unlock
@@ -5877,12 +5879,8 @@
Add account
Work profile isn\u2019t available yet
-
- Work profile
-
- Managed by your organization
-
- Apps and notifications are off
+
+ Work apps
Remove work profile
@@ -7175,7 +7173,7 @@
Docking sounds
- Touch sounds
+ Tap & click sounds
Always show icon when in vibrate mode
@@ -9783,6 +9781,8 @@
Cross-profile calendar
Show work events on your personal calendar
+
+ When work apps are off, they’re paused and can’t be accessed or send you notifications
Manage storage
@@ -10313,7 +10313,7 @@
Turn off this service?
- Save info like passwords, passkeys, payment methods, and other info won\'t be filled
+ Saved info like passwords, passkeys, payment methods, and other info won\'t be filled
in when you sign in. To use your saved info, choose a password, passkey, or data
service.
]]>
diff --git a/res/xml/bluetooth_audio_routing_fragment.xml b/res/xml/accessibility_audio_routing_fragment.xml
similarity index 85%
rename from res/xml/bluetooth_audio_routing_fragment.xml
rename to res/xml/accessibility_audio_routing_fragment.xml
index 5edf6cdca41..12e75f22ab1 100644
--- a/res/xml/bluetooth_audio_routing_fragment.xml
+++ b/res/xml/accessibility_audio_routing_fragment.xml
@@ -31,7 +31,7 @@
android:key="audio_routing_ringtone"
android:persistent="false"
android:title="@string/bluetooth_ringtone_title"
- settings:controller="com.android.settings.bluetooth.HearingDeviceRingtoneRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceRingtoneRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceCallRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceMediaRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceSystemSoundsRoutingPreferenceController" />
+
+
+
-
-
+ android:key="device_controls_general" />
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index 20f6d3dc3f3..ddfb86987ca 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -19,10 +19,9 @@
android:key="managed_profile_settings_screen"
android:title="@string/managed_profile_settings_title">
-
+
+
\ No newline at end of file
diff --git a/res/xml/reset_dashboard_fragment.xml b/res/xml/reset_dashboard_fragment.xml
index 98f6c02a8f2..3bd7a136760 100644
--- a/res/xml/reset_dashboard_fragment.xml
+++ b/res/xml/reset_dashboard_fragment.xml
@@ -38,9 +38,10 @@
settings:controller="com.android.settings.network.BluetoothWiFiResetPreferenceController" />
-
+ android:title="@string/reset_app_preferences"
+ settings:userRestriction="no_control_apps" />
deviceList = getConnectedHearingAidDeviceList();
- return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
- }
-
private int getConnectedHearingAidDeviceNum() {
- return getConnectedHearingAidDeviceList().size();
- }
-
- private List getConnectedHearingAidDeviceList() {
- if (!isHearingAidSupported()) {
- return new ArrayList<>();
- }
- final List deviceList = new ArrayList<>();
- final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
- if (hapClientProfile != null) {
- deviceList.addAll(hapClientProfile.getConnectedDevices());
- }
- final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- if (hearingAidProfile != null) {
- deviceList.addAll(hearingAidProfile.getConnectedDevices());
- }
- return deviceList.stream()
- .distinct()
- .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
- }
-
- private boolean isHearingAidSupported() {
- if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
- return false;
- }
- final List supportedList = mBluetoothAdapter.getSupportedProfiles();
- return supportedList.contains(BluetoothProfile.HEARING_AID)
- || supportedList.contains(BluetoothProfile.HAP_CLIENT);
- }
-
- private boolean isAnyHearingAidRelatedProfilesNotReady() {
- HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
- return true;
- }
- HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
- if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
- return true;
- }
- return false;
+ return mHelper.getConnectedHearingAidDeviceList().size();
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
index 547c4568991..33fef62f205 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
@@ -39,7 +39,7 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe
private static final String TAG = "AccessibilityHearingAidsFragment";
private static final String KEY_HEARING_OPTIONS_CATEGORY = "hearing_options_category";
- private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
+ private static final int SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX = 20;
private String mFeatureName;
public AccessibilityHearingAidsFragment() {
@@ -65,7 +65,7 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe
final View view = super.onCreateView(inflater, container, savedInstanceState);
final PreferenceCategory controlCategory = findPreference(KEY_HEARING_OPTIONS_CATEGORY);
// To move the shortcut preference under controlCategory need to remove the original added.
- mShortcutPreference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
+ mShortcutPreference.setOrder(SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX);
getPreferenceScreen().removePreference(mShortcutPreference);
controlCategory.addPreference(mShortcutPreference);
return view;
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 01158bf1e5b..b414addc41f 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -322,6 +322,18 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
getComponentName());
};
+ private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
+ int resId;
+ if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
+ resId = R.string.accessibility_shortcut_edit_summary_software;
+ } else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
+ resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
+ } else {
+ resId = R.string.accessibility_shortcut_edit_summary_software;
+ }
+ return context.getText(resId);
+ }
+
/**
* This method will be invoked when a button in the tutorial dialog is clicked.
*
@@ -429,11 +441,9 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
getComponentName().flattenToString(), AccessibilityUtil.UserShortcutType.SOFTWARE);
final List list = new ArrayList<>();
- final CharSequence softwareTitle = context.getText(
- R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.SOFTWARE)) {
- list.add(softwareTitle);
+ list.add(getSoftwareShortcutTypeSummary(context));
}
if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText(
@@ -443,7 +453,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
// Show software shortcut if first time to use.
if (list.isEmpty()) {
- list.add(softwareTitle);
+ list.add(getSoftwareShortcutTypeSummary(context));
}
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
diff --git a/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
new file mode 100644
index 00000000000..54022ef7f9e
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * 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.accessibility;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * The controller of the audio routing.
+ */
+public class HearingAidAudioRoutingPreferenceController extends BasePreferenceController {
+ public HearingAidAudioRoutingPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+}
diff --git a/src/com/android/settings/accessibility/HearingAidHelper.java b/src/com/android/settings/accessibility/HearingAidHelper.java
new file mode 100644
index 00000000000..66a37f8dd58
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidHelper.java
@@ -0,0 +1,114 @@
+/*
+ * 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.accessibility;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A helper class to get and check hearing aids and its status.
+ */
+public class HearingAidHelper {
+
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final LocalBluetoothProfileManager mProfileManager;
+ private final CachedBluetoothDeviceManager mCachedDeviceManager;
+
+ public HearingAidHelper(Context context) {
+ final LocalBluetoothManager localBluetoothManager =
+ com.android.settings.bluetooth.Utils.getLocalBluetoothManager(context);
+ mProfileManager = localBluetoothManager.getProfileManager();
+ mCachedDeviceManager = localBluetoothManager.getCachedDeviceManager();
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ /**
+ * Gets the connected hearing aids device whose profiles are
+ * {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}.
+ *
+ * @return a list of hearing aids {@link BluetoothDevice} objects
+ */
+ public List getConnectedHearingAidDeviceList() {
+ if (!isHearingAidSupported()) {
+ return new ArrayList<>();
+ }
+ final List deviceList = new ArrayList<>();
+ final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null) {
+ deviceList.addAll(hapClientProfile.getConnectedDevices());
+ }
+ final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null) {
+ deviceList.addAll(hearingAidProfile.getConnectedDevices());
+ }
+ return deviceList.stream()
+ .distinct()
+ .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
+ }
+
+ /**
+ * Gets the first connected hearing aids device.
+ *
+ * @return a {@link CachedBluetoothDevice} that is hearing aids device
+ */
+ public CachedBluetoothDevice getConnectedHearingAidDevice() {
+ final List deviceList = getConnectedHearingAidDeviceList();
+ return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
+ }
+
+ /**
+ * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+ * supported.
+ */
+ public boolean isHearingAidSupported() {
+ if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+ return false;
+ }
+ final List supportedList = mBluetoothAdapter.getSupportedProfiles();
+ return supportedList.contains(BluetoothProfile.HEARING_AID)
+ || supportedList.contains(BluetoothProfile.HAP_CLIENT);
+ }
+
+ /**
+ * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+ * profiles all ready.
+ */
+ public boolean isAllHearingAidRelatedProfilesReady() {
+ HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
+ return false;
+ }
+ HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
index e93863ae064..3599f4874c4 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
@@ -47,19 +47,24 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
private static final String TAG = "HARoutingBasePreferenceController";
private static final boolean DEBUG = false;
- private final HearingAidAudioRoutingHelper mHelper;
+ private final HearingAidAudioRoutingHelper mAudioRoutingHelper;
+ private final HearingAidHelper mHearingAidHelper;
public HearingDeviceAudioRoutingBasePreferenceController(Context context,
String preferenceKey) {
- super(context, preferenceKey);
- mHelper = new HearingAidAudioRoutingHelper(context);
+ this(context, preferenceKey,
+ new HearingAidAudioRoutingHelper(context),
+ new HearingAidHelper(context));
}
@VisibleForTesting
public HearingDeviceAudioRoutingBasePreferenceController(Context context,
- String preferenceKey, HearingAidAudioRoutingHelper helper) {
+ String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+ HearingAidHelper hearingAidHelper) {
super(context, preferenceKey);
- mHelper = helper;
+
+ mAudioRoutingHelper = audioRoutingHelper;
+ mHearingAidHelper = hearingAidHelper;
}
@Override
@@ -81,7 +86,11 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
final Integer routingValue = Ints.tryParse((String) newValue);
saveRoutingValue(mContext, routingValue);
- trySetAudioRoutingConfig(getSupportedAttributeList(), getHearingDevice(), routingValue);
+ final CachedBluetoothDevice device = mHearingAidHelper.getConnectedHearingAidDevice();
+ if (device != null) {
+ trySetAudioRoutingConfig(getSupportedAttributeList(),
+ mHearingAidHelper.getConnectedHearingAidDevice(), routingValue);
+ }
return true;
}
@@ -89,10 +98,10 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
private void trySetAudioRoutingConfig(int[] audioAttributes,
CachedBluetoothDevice hearingDevice,
@HearingAidAudioRoutingConstants.RoutingValue int routingValue) {
- final List supportedStrategies = mHelper.getSupportedStrategies(
- audioAttributes);
+ final List supportedStrategies =
+ mAudioRoutingHelper.getSupportedStrategies(audioAttributes);
final AudioDeviceAttributes hearingDeviceAttributes =
- mHelper.getMatchedHearingDeviceAttributes(hearingDevice);
+ mAudioRoutingHelper.getMatchedHearingDeviceAttributes(hearingDevice);
if (hearingDeviceAttributes == null) {
if (DEBUG) {
Log.d(TAG,
@@ -103,8 +112,8 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
return;
}
- final boolean status = mHelper.setPreferredDeviceRoutingStrategies(supportedStrategies,
- hearingDeviceAttributes, routingValue);
+ final boolean status = mAudioRoutingHelper.setPreferredDeviceRoutingStrategies(
+ supportedStrategies, hearingDeviceAttributes, routingValue);
if (!status) {
final List strategiesName = supportedStrategies.stream()
@@ -121,12 +130,6 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
*/
protected abstract int[] getSupportedAttributeList();
- /**
- * Gets the {@link CachedBluetoothDevice} hearing device that is used to configure audio
- * routing.
- */
- protected abstract CachedBluetoothDevice getHearingDevice();
-
/**
* Saves the routing value.
*
diff --git a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
similarity index 81%
rename from src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
index 4e5e1937b11..8ca266359c2 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -35,15 +35,6 @@ public class HearingDeviceCallRoutingPreferenceController extends
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
public int getAvailabilityStatus() {
return Utils.isVoiceCapable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
@@ -54,11 +45,6 @@ public class HearingDeviceCallRoutingPreferenceController extends
return HearingAidAudioRoutingConstants.CALL_ROUTING_ATTRIBUTES;
}
- @Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
@Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
diff --git a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
index 1ea36c783e2..cd99ce0c0d0 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -34,26 +34,12 @@ public class HearingDeviceMediaRoutingPreferenceController extends
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES;
}
- @Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
@Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
diff --git a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
similarity index 80%
rename from src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
index 006cb6b217a..3e8f79cec29 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -34,26 +34,12 @@ public class HearingDeviceRingtoneRoutingPreferenceController extends
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE;
}
- @Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
@Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
diff --git a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
similarity index 80%
rename from src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
index a66cfab93a0..1bc0090c7e9 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -35,26 +35,12 @@ public class HearingDeviceSystemSoundsRoutingPreferenceController extends
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES;
}
- @Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
@Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 201172575ed..12706712427 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -249,12 +249,18 @@ public class ToggleScreenMagnificationPreferenceFragment extends
super.onProcessArguments(arguments);
}
- private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
- if (!DeviceConfig.getBoolean(
+ private boolean isAlwaysOnSettingEnabled() {
+ final boolean defaultValue = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_magnification_always_on_enabled);
+
+ return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
"AlwaysOnMagnifier__enable_always_on_magnifier",
- false
- )) {
+ defaultValue
+ );
+ }
+ private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
+ if (!isAlwaysOnSettingEnabled()) {
return;
}
diff --git a/src/com/android/settings/accounts/ContactSearchPreferenceController.java b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
index 5e4ef48d7c2..87dabd8d9a4 100644
--- a/src/com/android/settings/accounts/ContactSearchPreferenceController.java
+++ b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
@@ -20,37 +20,38 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
import com.android.settings.slices.SliceData;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference;
-public class ContactSearchPreferenceController extends BasePreferenceController implements
- Preference.OnPreferenceChangeListener {
+import org.jetbrains.annotations.NotNull;
- private UserHandle mManagedUser;
+public class ContactSearchPreferenceController extends TogglePreferenceController implements
+ Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+ ManagedProfileQuietModeEnabler.QuietModeChangeListener {
+
+ private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
+ private final UserHandle mManagedUser;
+ private Preference mPreference;
public ContactSearchPreferenceController(Context context, String key) {
super(context, key);
- // Set default managed profile for the current user, otherwise isAvailable will be false and
- // the setting won't be searchable.
- UserManager userManager = context.getSystemService(UserManager.class);
- mManagedUser = Utils.getManagedProfile(userManager);
- }
-
- @VisibleForTesting
- void setManagedUser(UserHandle managedUser) {
- mManagedUser = managedUser;
+ mManagedUser = Utils.getManagedProfile(context.getSystemService(UserManager.class));
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
- return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+ return mQuietModeEnabler.isAvailable() ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
@@ -59,6 +60,7 @@ public class ContactSearchPreferenceController extends BasePreferenceController
if (preference instanceof RestrictedSwitchPreference) {
final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setChecked(isChecked());
+ pref.setEnabled(!mQuietModeEnabler.isQuietModeEnabled());
if (mManagedUser != null) {
final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
RestrictedLockUtilsInternal.checkIfRemoteContactSearchDisallowed(
@@ -68,26 +70,48 @@ public class ContactSearchPreferenceController extends BasePreferenceController
}
}
- private boolean isChecked() {
- if (mManagedUser == null) {
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ updateState(mPreference);
+ }
+
+ @Override
+ public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
+ }
+
+ @Override
+ public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
+ }
+
+ @Override
+ public boolean isChecked() {
+ if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
return false;
}
return 0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
}
- private boolean setChecked(boolean isChecked) {
- if (mManagedUser != null) {
- final int value = isChecked ? 1 : 0;
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
+ return false;
}
+ final int value = isChecked ? 1 : 0;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
return true;
}
@Override
- public final boolean onPreferenceChange(Preference preference, Object newValue) {
- return setChecked((boolean) newValue);
+ public void onQuietModeChanged() {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
}
@Override
@@ -95,4 +119,9 @@ public class ContactSearchPreferenceController extends BasePreferenceController
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
-}
\ No newline at end of file
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accounts;
+ }
+}
diff --git a/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
new file mode 100644
index 00000000000..989be09565c
--- /dev/null
+++ b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
@@ -0,0 +1,122 @@
+/*
+ * 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.accounts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.Utils;
+
+import javax.annotation.Nullable;
+
+/**
+ * A class that controls the managed profile's quiet mode, listens to quiet mode changes and
+ * modifies managed profile settings. The user facing term for quiet mode is "work apps".
+ */
+final class ManagedProfileQuietModeEnabler implements DefaultLifecycleObserver {
+
+ private static final String TAG = "QuietModeEnabler";
+ private final Context mContext;
+ private final QuietModeChangeListener mListener;
+ @Nullable private final UserHandle mManagedProfile;
+ private final UserManager mUserManager;
+
+ public interface QuietModeChangeListener {
+ /** Called when quiet mode has changed. */
+ void onQuietModeChanged();
+ }
+
+ ManagedProfileQuietModeEnabler(Context context, QuietModeChangeListener listener) {
+ mContext = context;
+ mListener = listener;
+ mUserManager = context.getSystemService(UserManager.class);
+ mManagedProfile = Utils.getManagedProfile(mUserManager);
+ }
+
+ public void setQuietModeEnabled(boolean enabled) {
+ if (mManagedProfile != null) {
+ mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
+ }
+ }
+
+ public boolean isQuietModeEnabled() {
+ return mManagedProfile != null && mUserManager.isQuietModeEnabled(mManagedProfile);
+ }
+
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ public boolean isAvailable() {
+ return (mManagedProfile != null);
+ }
+
+ private void refreshQuietMode() {
+ if (mListener != null) {
+ mListener.onQuietModeChanged();
+ }
+ }
+
+ /**
+ * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
+ * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ String action = intent.getAction();
+ Log.v(TAG, "Received broadcast: " + action);
+
+ if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+ int intentUserIdentifier = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (intentUserIdentifier == mManagedProfile.getIdentifier()) {
+ refreshQuietMode();
+ } else {
+ Log.w(TAG, "Managed profile broadcast ID: " + intentUserIdentifier
+ + " does not match managed user: " + mManagedProfile);
+ }
+ } else {
+ Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
+ }
+ }
+ };
+}
diff --git a/src/com/android/settings/accounts/WorkModePreferenceController.java b/src/com/android/settings/accounts/WorkModePreferenceController.java
index 1941de45c4d..a261afccaa6 100644
--- a/src/com/android/settings/accounts/WorkModePreferenceController.java
+++ b/src/com/android/settings/accounts/WorkModePreferenceController.java
@@ -1,165 +1,90 @@
/*
* Copyright (C) 2018 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
+ * 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.
+ * 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.accounts;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.TwoStatePreference;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
import com.android.settings.slices.SliceData;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settings.widget.SettingsMainSwitchPreferenceController;
+import com.android.settingslib.widget.MainSwitchPreference;
-public class WorkModePreferenceController extends BasePreferenceController implements
- Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart, OnStop {
+import org.jetbrains.annotations.NotNull;
- private static final String TAG = "WorkModeController";
- private UserManager mUserManager;
- private UserHandle mManagedUser;
- private DevicePolicyManager mDevicePolicyManager;
+public class WorkModePreferenceController extends SettingsMainSwitchPreferenceController
+ implements Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+ ManagedProfileQuietModeEnabler.QuietModeChangeListener {
- private Preference mPreference;
- private IntentFilter mIntentFilter;
+ private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
public WorkModePreferenceController(Context context, String key) {
super(context, key);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
- mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- // Set default managed profile for the current user, otherwise isAvailable will be false and
- // the setting won't be searchable.
- mManagedUser = Utils.getManagedProfile(mUserManager);
- }
-
- @VisibleForTesting
- void setManagedUser(UserHandle managedUser) {
- mManagedUser = managedUser;
- }
-
- @Override
- public void onStart() {
- mContext.registerReceiver(mReceiver, mIntentFilter,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
- @Override
- public void onStop() {
- mContext.unregisterReceiver(mReceiver);
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
- return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+ return (mQuietModeEnabler.isAvailable()) ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
+ public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
}
@Override
- public CharSequence getSummary() {
- if (isChecked()) {
- return mDevicePolicyManager.getResources().getString(
- WORK_PROFILE_SETTING_ON_SUMMARY,
- () -> mContext.getString(R.string.work_mode_on_summary));
- }
-
- return mDevicePolicyManager.getResources().getString(
- WORK_PROFILE_SETTING_OFF_SUMMARY,
- () -> mContext.getString(R.string.work_mode_off_summary));
+ public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
}
- private boolean isChecked() {
- boolean isWorkModeOn = false;
- if (mUserManager != null && mManagedUser != null) {
- isWorkModeOn = !mUserManager.isQuietModeEnabled(mManagedUser);
- }
- return isWorkModeOn;
+ @Override
+ public boolean isChecked() {
+ return !mQuietModeEnabler.isQuietModeEnabled();
}
- private boolean setChecked(boolean isChecked) {
- if (mUserManager != null && mManagedUser != null) {
- final boolean quietModeEnabled = !isChecked;
- mUserManager.requestQuietModeEnabled(quietModeEnabled, mManagedUser);
- }
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ mQuietModeEnabler.setQuietModeEnabled(!isChecked);
return true;
}
@Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- if (preference instanceof TwoStatePreference) {
- ((TwoStatePreference) preference).setChecked(isChecked());
- }
+ public void onQuietModeChanged() {
+ updateState(mSwitchPreference);
}
- @Override
- public final boolean onPreferenceChange(Preference preference, Object newValue) {
- return setChecked((boolean) newValue);
- }
-
- /**
- * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
- * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
- */
- @VisibleForTesting
- final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
- final String action = intent.getAction();
- Log.v(TAG, "Received broadcast: " + action);
-
- if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
- || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
- if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL) == mManagedUser.getIdentifier()) {
- updateState(mPreference);
- }
- return;
- }
- Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
- }
- };
-
@Override
@SliceData.SliceType
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
-}
\ No newline at end of file
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accounts;
+ }
+
+ @VisibleForTesting
+ void setPreference(MainSwitchPreference preference) {
+ mSwitchPreference = preference;
+ }
+}
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index ae890f87632..67d56e0393a 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -97,16 +97,24 @@ public class ActivityEmbeddingUtils {
*
*/
public static boolean isEmbeddingActivityEnabled(Context context) {
- boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context,
- FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN);
- boolean isSettingsSplitSupported = isSettingsSplitEnabled(context);
- boolean isUserSetupComplete = WizardManagerHelper.isUserSetupComplete(context);
-
- Log.d(TAG, "isFlagEnabled = " + isFlagEnabled);
- Log.d(TAG, "isSettingsSplitSupported = " + isSettingsSplitSupported);
- Log.d(TAG, "isUserSetupComplete = " + isUserSetupComplete);
-
- return isFlagEnabled && isSettingsSplitSupported && isUserSetupComplete;
+ // Activity Embedding feature is not enabled if Settings doesn't enable large screen
+ // optimization or the device is not supported.
+ if (!isSettingsSplitEnabled(context)) {
+ Log.d(TAG, "isSettingsSplitSupported = false");
+ return false;
+ }
+ // Activity Embedding feature is not enabled if a user chooses to disable the feature.
+ if (!FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
+ Log.d(TAG, "isFlagEnabled = false");
+ return false;
+ }
+ // Don't enable Activity embedding for setup wizard.
+ if (!WizardManagerHelper.isUserSetupComplete(context)) {
+ Log.d(TAG, "isUserSetupComplete = false");
+ return false;
+ }
+ Log.d(TAG, "isEmbeddingActivityEnabled = true");
+ return true;
}
/** Whether to show the regular or simplified homepage layout. */
@@ -120,8 +128,7 @@ public class ActivityEmbeddingUtils {
* Check if activity is already embedded
*/
public static boolean isAlreadyEmbedded(Activity activity) {
- return ActivityEmbeddingController
- .getInstance(activity)
- .isActivityEmbedded(activity);
+ return isEmbeddingActivityEnabled(activity) && ActivityEmbeddingController.getInstance(
+ activity).isActivityEmbedded(activity);
}
}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index a6e6ac47673..e0f1b5f702d 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -16,8 +16,6 @@
package com.android.settings.applications.manageapplications;
-import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_SPA;
-
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
@@ -67,7 +65,6 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.LayoutInflater;
@@ -728,9 +725,6 @@ public class ManageApplications extends InstrumentedFragment
R.string.long_background_tasks_label);
break;
case LIST_TYPE_CLONED_APPS:
- if (!FeatureFlagUtils.isEnabled(getContext(), SETTINGS_ENABLE_SPA)) {
- return;
- }
int userId = UserHandle.getUserId(mCurrentUid);
UserInfo userInfo = mUserManager.getUserInfo(userId);
if (userInfo != null && !userInfo.isCloneProfile()) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index bf83cb15f21..938c075cb70 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -261,6 +261,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
int rotation = getApplicationContext().getDisplay().getRotation();
final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate(
R.layout.udfps_enroll_enrolling, null, false);
+ final UdfpsEnrollView udfpsEnrollView = layout.findViewById(R.id.udfps_animation_view);
+ updateUdfpsEnrollView(udfpsEnrollView, props.get(0));
switch (rotation) {
case Surface.ROTATION_90:
final LinearLayout layoutContainer = layout.findViewById(
@@ -276,66 +278,52 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
? 0 : (int) getResources().getDimension(
R.dimen.rotation_90_enroll_padding_end), 0);
layoutContainer.setLayoutParams(lp);
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- layout.addView(udfpsEnrollView);
- setOnHoverListener(true, layout, udfpsEnrollView);
- }
+
+ setOnHoverListener(true, layout, udfpsEnrollView);
setContentView(layout, lp);
break;
case Surface.ROTATION_0:
case Surface.ROTATION_180:
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- // In the portrait mode, set layout_container's height 0, so it's
- // always shown at the bottom of the screen.
- // Add udfps enroll view into layout_container instead of
- // udfps_enroll_enrolling, so that when the content is too long to
- // make udfps_enroll_enrolling larger than the screen, udfps enroll
- // view could still be set to right position by setting bottom margin to
- // its parent view (layout_container) because it's always at the
- // bottom of the screen.
- final FrameLayout portraitLayoutContainer = layout.findViewById(
- R.id.layout_container);
- final ViewGroup.LayoutParams containerLp =
- portraitLayoutContainer.getLayoutParams();
- containerLp.height = 0;
+ // In the portrait mode, layout_container's height is 0, so it's
+ // always shown at the bottom of the screen.
+ final FrameLayout portraitLayoutContainer = layout.findViewById(
+ R.id.layout_container);
- // In the portrait mode, the title and lottie animation view may
- // overlap when title needs three lines, so adding some paddings
- // between them, and adjusting the fp progress view here accordingly.
- final int layoutLottieAnimationPadding = (int) getResources()
- .getDimension(R.dimen.udfps_lottie_padding_top);
- portraitLayoutContainer.setPadding(0,
- layoutLottieAnimationPadding, 0, 0);
- final ImageView progressView = udfpsEnrollView.findViewById(
- R.id.udfps_enroll_animation_fp_progress_view);
- progressView.setPadding(0, -(layoutLottieAnimationPadding),
- 0, layoutLottieAnimationPadding);
- final ImageView fingerprintView = udfpsEnrollView.findViewById(
- R.id.udfps_enroll_animation_fp_view);
- fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
- 0, layoutLottieAnimationPadding);
+ // In the portrait mode, the title and lottie animation view may
+ // overlap when title needs three lines, so adding some paddings
+ // between them, and adjusting the fp progress view here accordingly.
+ final int layoutLottieAnimationPadding = (int) getResources()
+ .getDimension(R.dimen.udfps_lottie_padding_top);
+ portraitLayoutContainer.setPadding(0,
+ layoutLottieAnimationPadding, 0, 0);
+ final ImageView progressView = udfpsEnrollView.findViewById(
+ R.id.udfps_enroll_animation_fp_progress_view);
+ progressView.setPadding(0, -(layoutLottieAnimationPadding),
+ 0, layoutLottieAnimationPadding);
+ final ImageView fingerprintView = udfpsEnrollView.findViewById(
+ R.id.udfps_enroll_animation_fp_view);
+ fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
+ 0, layoutLottieAnimationPadding);
- portraitLayoutContainer.addView(udfpsEnrollView);
- setOnHoverListener(false, layout, udfpsEnrollView);
- }
+ // TODO(b/260970216) Instead of hiding the description text view, we should
+ // make the header view scrollable if the text is too long.
+ // If description text view has overlap with udfps progress view, hide it.
+ View view = layout.getDescriptionTextView();
+ layout.getViewTreeObserver().addOnDrawListener(() -> {
+ if (view.getVisibility() == View.VISIBLE
+ && hasOverlap(view, udfpsEnrollView)) {
+ view.setVisibility(View.GONE);
+ }
+ });
+ setOnHoverListener(false, layout, udfpsEnrollView);
setContentView(layout);
break;
case Surface.ROTATION_270:
default:
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- layout.addView(udfpsEnrollView);
- setOnHoverListener(true, layout, udfpsEnrollView);
- }
-
+ setOnHoverListener(true, layout, udfpsEnrollView);
setContentView(layout);
break;
}
@@ -1235,10 +1223,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
}
}
- private UdfpsEnrollView addUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps) {
- UdfpsEnrollView udfpsEnrollView = (UdfpsEnrollView) getLayoutInflater().inflate(
- R.layout.udfps_enroll_view, null, false);
-
+ private UdfpsEnrollView updateUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
+ FingerprintSensorPropertiesInternal udfpsProps) {
DisplayInfo displayInfo = new DisplayInfo();
getDisplay().getDisplayInfo(displayInfo);
mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
@@ -1305,6 +1291,24 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
: R.id.sud_layout_content).setOnHoverListener(onHoverListener);
}
+
+ @VisibleForTesting boolean hasOverlap(View view1, View view2) {
+ int[] firstPosition = new int[2];
+ int[] secondPosition = new int[2];
+
+ view1.getLocationOnScreen(firstPosition);
+ view2.getLocationOnScreen(secondPosition);
+
+ // Rect constructor parameters: left, top, right, bottom
+ Rect rectView1 = new Rect(firstPosition[0], firstPosition[1],
+ firstPosition[0] + view1.getMeasuredWidth(),
+ firstPosition[1] + view1.getMeasuredHeight());
+ Rect rectView2 = new Rect(secondPosition[0], secondPosition[1],
+ secondPosition[0] + view2.getMeasuredWidth(),
+ secondPosition[1] + view2.getMeasuredHeight());
+ return rectView1.intersect(rectView2);
+ }
+
public static class IconTouchDialog extends InstrumentedDialogFragment {
@Override
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index e0f402bdc02..be090e33366 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -185,7 +185,8 @@ public class FingerprintSettings extends SubSettings {
private static final int MSG_FINGER_AUTH_HELP = 1004;
private static final int CONFIRM_REQUEST = 101;
- private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
+ @VisibleForTesting
+ static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
@VisibleForTesting
static final int ADD_FINGERPRINT_REQUEST = 10;
private static final int AUTO_ADD_FIRST_FINGERPRINT_REQUEST = 11;
@@ -1014,7 +1015,7 @@ public class FingerprintSettings extends SubSettings {
true);
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
- intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
index 6e42059395f..5ded91ec68c 100644
--- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
+++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
@@ -161,22 +161,20 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams();
FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams();
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
- parentView.getViewTreeObserver().addOnDrawListener(() -> {
- final int[] coords = parentView.getLocationOnScreen();
- final int parentLeft = coords[0];
- final int parentTop = coords[1];
- final int parentRight = parentLeft + parentView.getWidth();
- params.gravity = Gravity.RIGHT | Gravity.TOP;
- final int rightMargin = parentRight - rotatedBounds.right - getPaddingX();
- final int topMargin = rotatedBounds.top - parentTop - getPaddingY();
- if (marginLayoutParams.rightMargin == rightMargin
- && marginLayoutParams.topMargin == topMargin) {
- return;
- }
- marginLayoutParams.rightMargin = rightMargin;
- marginLayoutParams.topMargin = topMargin;
- setLayoutParams(params);
- });
+ final int[] coords = parentView.getLocationOnScreen();
+ final int parentLeft = coords[0];
+ final int parentTop = coords[1];
+ final int parentRight = parentLeft + parentView.getWidth();
+ params.gravity = Gravity.RIGHT | Gravity.TOP;
+ final int rightMargin = parentRight - rotatedBounds.right - getPaddingX();
+ final int topMargin = rotatedBounds.top - parentTop - getPaddingY();
+ if (marginLayoutParams.rightMargin == rightMargin
+ && marginLayoutParams.topMargin == topMargin) {
+ return;
+ }
+ marginLayoutParams.rightMargin = rightMargin;
+ marginLayoutParams.topMargin = topMargin;
+ setLayoutParams(params);
} else {
final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0];
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
deleted file mode 100644
index 91221a33ba9..00000000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.FeatureFlagUtils;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-/**
- * The controller of the audio routing in the bluetooth detail settings.
- */
-public class BluetoothDetailsAudioRoutingController extends BluetoothDetailsController {
-
- private static final String KEY_DEVICE_CONTROLS_SPECIFIC_GROUP = "device_controls_specific";
- @VisibleForTesting
- static final String KEY_AUDIO_ROUTING = "audio_routing";
-
- public BluetoothDetailsAudioRoutingController(Context context,
- PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle) {
- super(context, fragment, device, lifecycle);
- }
-
- @Override
- public boolean isAvailable() {
- return mCachedDevice.isHearingAidDevice() && FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING);
- }
-
- @Override
- protected void init(PreferenceScreen screen) {
- if (!mCachedDevice.isHearingAidDevice()) {
- return;
- }
-
- final PreferenceCategory prefCategory = screen.findPreference(getPreferenceKey());
- final Preference pref = createAudioRoutingPreference(prefCategory.getContext());
- prefCategory.addPreference(pref);
- }
-
- @Override
- protected void refresh() {}
-
- @Override
- public String getPreferenceKey() {
- return KEY_DEVICE_CONTROLS_SPECIFIC_GROUP;
- }
-
- private Preference createAudioRoutingPreference(Context context) {
- final Preference preference = new Preference(context);
-
- preference.setKey(KEY_AUDIO_ROUTING);
- preference.setTitle(context.getString(R.string.bluetooth_audio_routing_title));
- preference.setSummary(context.getString(R.string.bluetooth_audio_routing_summary));
- final Bundle extras = preference.getExtras();
- extras.putString(KEY_DEVICE_ADDRESS, mCachedDevice.getAddress());
- preference.setFragment(BluetoothDetailsAudioRoutingFragment.class.getName());
-
- return preference;
- }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
deleted file mode 100644
index 6c435a27cd2..00000000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
+++ /dev/null
@@ -1,87 +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.bluetooth;
-
-import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.app.settings.SettingsEnums;
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settings.dashboard.RestrictedDashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-/** Settings fragment containing bluetooth audio routing. */
-public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFragment {
-
- public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.bluetooth_audio_routing_fragment);
- private static final String TAG = "BluetoothDetailsAudioRoutingFragment";
- @VisibleForTesting
- CachedBluetoothDevice mCachedDevice;
-
- public BluetoothDetailsAudioRoutingFragment() {
- super(DISALLOW_CONFIG_BLUETOOTH);
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- final LocalBluetoothManager localBtMgr = Utils.getLocalBtManager(context);
- final CachedBluetoothDeviceManager cachedDeviceMgr = localBtMgr.getCachedDeviceManager();
- final BluetoothDevice bluetoothDevice = localBtMgr.getBluetoothAdapter().getRemoteDevice(
- getArguments().getString(KEY_DEVICE_ADDRESS));
-
- mCachedDevice = cachedDeviceMgr.findDevice(bluetoothDevice);
- if (mCachedDevice == null) {
- // Close this page if device is null with invalid device mac address
- Log.w(TAG, "onAttach() CachedDevice is null! Can not find address: "
- + bluetoothDevice.getAnonymizedAddress());
- finish();
- return;
- }
-
- use(HearingDeviceRingtoneRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceCallRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceMediaRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceSystemSoundsRoutingPreferenceController.class).init(mCachedDevice);
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.BLUETOOTH_AUDIO_ROUTING;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.bluetooth_audio_routing_fragment;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index a3b1105015d..c4a422186dd 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -34,7 +34,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import com.google.common.annotations.VisibleForTesting;
/**
- * The controller of the hearing device controls in the bluetooth detail settings.
+ * The controller of the hearing device settings to launch Hearing device page.
*/
public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener {
@@ -87,6 +87,7 @@ public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDe
final Preference preference = new Preference(context);
preference.setKey(KEY_HEARING_DEVICE_CONTROLS);
preference.setTitle(context.getString(R.string.bluetooth_device_controls_title));
+ preference.setSummary(context.getString(R.string.bluetooth_device_controls_summary));
preference.setOnPreferenceClickListener(this);
return preference;
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 2a94b1e077e..99f3e3187cb 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -314,8 +314,6 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
lifecycle));
controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
mCachedDevice, lifecycle));
- controllers.add(new BluetoothDetailsAudioRoutingController(context, this, mCachedDevice,
- lifecycle));
}
return controllers;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index 17c5f36d5c6..2935c6779dc 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -35,8 +35,10 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -125,7 +127,7 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
update(cachedBluetoothDevice);
}
} else {
- removeAllDevicesFromPreference();
+ removeAllDevicesFromPreference();
}
}
@@ -252,7 +254,7 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
btPreference.setOnGearClickListener(mDeviceProfilesListener);
if (this instanceof Preference.OnPreferenceClickListener) {
btPreference.setOnPreferenceClickListener(
- (Preference.OnPreferenceClickListener)this);
+ (Preference.OnPreferenceClickListener) this);
}
mPreferenceMap.put(device, btPreference);
mDevicePreferenceCallback.onDeviceAdded(btPreference);
@@ -266,17 +268,20 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
final BluetoothDevice device = cachedDevice.getDevice();
final CachedBluetoothDevice subCachedDevice = cachedDevice.getSubDevice();
if (mPreferenceMap.containsKey(device)) {
- mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
- mPreferenceMap.remove(device);
+ removePreference(device);
} else if (subCachedDevice != null) {
// When doing remove, to check if preference maps to sub device.
// This would happen when connection state is changed in detail page that there is no
// callback from SettingsLib.
final BluetoothDevice subDevice = subCachedDevice.getDevice();
- if (mPreferenceMap.containsKey(subDevice)) {
- mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(subDevice));
- mPreferenceMap.remove(subDevice);
- }
+ removePreference(subDevice);
+ }
+ }
+
+ private void removePreference(BluetoothDevice device) {
+ if (mPreferenceMap.containsKey(device)) {
+ mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
+ mPreferenceMap.remove(device);
}
}
@@ -324,14 +329,38 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
* Update the attributes of {@link Preference}.
*/
public void refreshPreference() {
- for (Preference preference : mPreferenceMap.values()) {
- ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+ List removeList = new ArrayList<>();
+ mPreferenceMap.forEach((key, preference) -> {
+ if (isDeviceOfMapInCachedDevicesList(key)) {
+ ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+ } else {
+ // If the BluetoothDevice of preference is not in the CachedDevices List, then
+ // remove this preference.
+ removeList.add(key);
+ }
+ });
+
+ for (BluetoothDevice bluetoothDevice : removeList) {
+ Log.d(getLogTag(), "removePreference key: " + bluetoothDevice.getAnonymizedAddress());
+ removePreference(bluetoothDevice);
}
}
- protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice){
+ protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice) {
return mLocalManager.getCachedDeviceManager().getCachedDevicesCopy().contains(cachedDevice);
}
+
+ private boolean isDeviceOfMapInCachedDevicesList(BluetoothDevice inputBluetoothDevice) {
+ Collection cachedDevices =
+ mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+ if (cachedDevices == null || cachedDevices.isEmpty()) {
+ return false;
+ }
+ return cachedDevices.stream()
+ .anyMatch(cachedBluetoothDevice -> cachedBluetoothDevice.getDevice() != null
+ && cachedBluetoothDevice.getDevice().equals(inputBluetoothDevice));
+ }
+
protected String getLogTag() {
return TAG;
}
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
index b9f34137111..04252fa0d56 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
@@ -48,6 +48,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
private final DevelopmentSettingsDashboardFragment mFragment;
+ private final GraphicsDriverSystemPropertiesWrapper mSystemProperties;
+
@VisibleForTesting
static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@@ -57,11 +59,34 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@VisibleForTesting
static final String ANGLE_DRIVER_SUFFIX = "angle";
+ @VisibleForTesting
+ static class Injector {
+ public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return new GraphicsDriverSystemPropertiesWrapper() {
+ @Override
+ public String get(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+
+ @Override
+ public void set(String key, String val) {
+ SystemProperties.set(key, val);
+ }
+ };
+ }
+ }
public GraphicsDriverEnableAngleAsSystemDriverController(
Context context, DevelopmentSettingsDashboardFragment fragment) {
+ this(context, fragment, new Injector());
+ }
+
+ @VisibleForTesting
+ GraphicsDriverEnableAngleAsSystemDriverController(
+ Context context, DevelopmentSettingsDashboardFragment fragment, Injector injector) {
super(context);
mFragment = fragment;
+ mSystemProperties = injector.createSystemPropertiesWrapper();
}
@Override
@@ -76,20 +101,27 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
// set "persist.graphics.egl" to "" if enableAngleAsSystemDriver is false
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(enableAngleAsSystemDriver);
// pop up a window asking user to reboot to make the new "persist.graphics.egl" take effect
+ showRebootDialog();
+ return true;
+ }
+
+ @VisibleForTesting
+ void showRebootDialog() {
RebootConfirmationDialogFragment.show(
mFragment, R.string.reboot_dialog_enable_angle_as_system_driver,
R.string.cancel, this);
- return true;
}
+
@Override
public void updateState(Preference preference) {
// set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
// set switch off otherwise.
- final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ final String currentGlesDriver =
+ mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
- final boolean isAngleSupported =
- TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true");
+ final boolean isAngleSupported = TextUtils
+ .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported);
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -98,8 +130,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
protected void onDeveloperOptionsSwitchEnabled() {
// only enable the switch if ro.gfx.angle.supported is true
// we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor
- final boolean isAngleSupported =
- TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true");
+ final boolean isAngleSupported = TextUtils
+ .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -116,7 +148,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@Override
public void onRebootCancelled() {
// if user presses button "Cancel", do not reboot the device, and toggles switch back
- final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ final String currentGlesDriver =
+ mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
if (TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver)) {
// if persist.graphics.egl = "angle", set the property value back to ""
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java
new file mode 100644
index 00000000000..549cd81c565
--- /dev/null
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.development.graphicsdriver;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+interface GraphicsDriverSystemPropertiesWrapper {
+ /**
+ * Get the String value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
+ */
+ @NonNull
+ String get(@NonNull String key, @Nullable String def);
+ /**
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+ * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+ * SELinux. libc will log the underlying reason.
+ */
+ void set(@NonNull String key, @Nullable String val);
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 98240447aeb..300db23007c 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -322,18 +322,11 @@ public class BatteryInfo {
final long drainTimeUs = PowerUtil.convertMsToUs(estimate.getEstimateMillis());
if (drainTimeUs > 0) {
info.remainingTimeUs = drainTimeUs;
- info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(
+ info.remainingLabel = PowerUtil.getBatteryRemainingShortStringFormatted(
context,
- PowerUtil.convertUsToMs(drainTimeUs),
- null /* percentageString */,
- false /* basedOnUsage */
- );
- info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(
- context,
- PowerUtil.convertUsToMs(drainTimeUs),
- info.batteryPercentString,
- estimate.isBasedOnUsage() && !shortString
+ PowerUtil.convertUsToMs(drainTimeUs)
);
+ info.chargeLabel = info.remainingLabel;
info.suggestionLabel = PowerUtil.getBatteryTipStringFormatted(
context, PowerUtil.convertUsToMs(drainTimeUs));
} else {
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 03bc1b32fb2..829a89c6f03 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -57,7 +57,6 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
-import androidx.window.embedding.ActivityEmbeddingController;
import androidx.window.embedding.SplitRule;
import com.android.settings.R;
@@ -108,7 +107,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
private View mTwoPaneSuggestionView;
private CategoryMixin mCategoryMixin;
private Set mLoadedListeners;
- private ActivityEmbeddingController mActivityEmbeddingController;
private boolean mIsEmbeddingActivityEnabled;
private boolean mIsTwoPane;
// A regular layout shows icons on homepage, whereas a simplified layout doesn't.
@@ -200,8 +198,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
setupEdgeToEdge();
setContentView(R.layout.settings_homepage_container);
- mActivityEmbeddingController = ActivityEmbeddingController.getInstance(this);
- mIsTwoPane = mActivityEmbeddingController.isActivityEmbedded(this);
+ mIsTwoPane = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
updateAppBarMinHeight();
initHomepageContainer();
@@ -242,7 +239,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
// Settings app may be launched on an existing task. Reset SplitPairRule of SubSettings here
// to prevent SplitPairRule of an existing task applied on a new started Settings app.
- if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)
+ if (mIsEmbeddingActivityEnabled
&& (getIntent().getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
initSplitPairRules();
}
@@ -284,7 +281,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- final boolean newTwoPaneState = mActivityEmbeddingController.isActivityEmbedded(this);
+ final boolean newTwoPaneState = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
if (mIsTwoPane != newTwoPaneState) {
mIsTwoPane = newTwoPaneState;
updateHomepageAppBar();
@@ -427,8 +424,9 @@ public class SettingsHomepageActivity extends FragmentActivity implements
}
private boolean shouldLaunchDeepLinkIntentToRight() {
- if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
- || !ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
+ if (!ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
+ || !FeatureFlagUtils.isEnabled(this,
+ FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
return false;
}
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
index 2dc09bd9ee0..ad9e10f19ed 100644
--- a/src/com/android/settings/localepicker/LocaleDialogFragment.java
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -21,8 +21,8 @@ import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
-import android.os.ResultReceiver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +35,6 @@ import androidx.fragment.app.FragmentManager;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -46,49 +45,19 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class LocaleDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = LocaleDialogFragment.class.getSimpleName();
- static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
- static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
+ static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+ static final int DIALOG_NOT_AVAILABLE_LOCALE = 2;
static final String ARG_DIALOG_TYPE = "arg_dialog_type";
static final String ARG_TARGET_LOCALE = "arg_target_locale";
- static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
+ static final String ARG_SHOW_DIALOG = "arg_show_dialog";
+
+ private boolean mShouldKeepDialog;
public static LocaleDialogFragment newInstance() {
return new LocaleDialogFragment();
}
- /**
- * Show dialog
- */
- public void show(
- @NonNull RestrictedSettingsFragment fragment,
- int dialogType,
- LocaleStore.LocaleInfo localeInfo) {
- if (!isAdded()) {
- return;
- }
- show(fragment, dialogType, localeInfo, null);
- }
-
- /**
- * Show dialog
- */
- public void show(
- @NonNull RestrictedSettingsFragment fragment,
- int dialogType,
- LocaleStore.LocaleInfo localeInfo,
- ResultReceiver resultReceiver) {
- FragmentManager manager = fragment.getChildFragmentManager();
- Bundle args = new Bundle();
- args.putInt(ARG_DIALOG_TYPE, dialogType);
- args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
- args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
-
- LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
- localeDialogFragment.setArguments(args);
- localeDialogFragment.show(manager, TAG);
- }
-
@Override
public int getMetricsCategory() {
int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
@@ -102,9 +71,29 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
}
}
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(ARG_SHOW_DIALOG, mShouldKeepDialog);
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- LocaleDialogController controller = new LocaleDialogController(this);
+ if (savedInstanceState != null) {
+ Bundle arguments = getArguments();
+ int type = arguments.getInt(ARG_DIALOG_TYPE);
+ mShouldKeepDialog = savedInstanceState.getBoolean(ARG_SHOW_DIALOG, false);
+ // Keep the dialog if user rotates the device, otherwise close the confirm system
+ // default dialog only when user changes the locale.
+ if (type == DIALOG_CONFIRM_SYSTEM_DEFAULT && !mShouldKeepDialog) {
+ dismiss();
+ }
+ }
+
+ mShouldKeepDialog = true;
+ LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment();
+ LocaleDialogController controller = getLocaleDialogController(getContext(), this,
+ parentFragment);
LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
R.layout.locale_dialog, null);
@@ -140,47 +129,57 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
textView.setText(content);
}
- static class LocaleDialogController implements DialogInterface.OnClickListener {
+ @VisibleForTesting
+ LocaleDialogController getLocaleDialogController(Context context,
+ LocaleDialogFragment dialogFragment, LocaleListEditor parentFragment) {
+ return new LocaleDialogController(context, dialogFragment, parentFragment);
+ }
+
+ class LocaleDialogController implements DialogInterface.OnClickListener {
private final Context mContext;
private final int mDialogType;
private final LocaleStore.LocaleInfo mLocaleInfo;
- private final ResultReceiver mResultReceiver;
private final MetricsFeatureProvider mMetricsFeatureProvider;
+ private LocaleListEditor mParent;
+
LocaleDialogController(
- @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
+ @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment,
+ LocaleListEditor parentFragment) {
mContext = context;
Bundle arguments = dialogFragment.getArguments();
mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
- mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
- ARG_TARGET_LOCALE);
- mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
+ mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE);
mMetricsFeatureProvider = FeatureFactory.getFactory(
mContext).getMetricsFeatureProvider();
+ mParent = parentFragment;
}
- LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
- this(dialogFragment.getContext(), dialogFragment);
+ LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment,
+ LocaleListEditor parent) {
+ this(dialogFragment.getContext(), dialogFragment, parent);
}
@Override
public void onClick(DialogInterface dialog, int which) {
- if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ if (mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ int result = Activity.RESULT_CANCELED;
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ result = Activity.RESULT_OK;
+ }
+ Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
- if (which == DialogInterface.BUTTON_POSITIVE) {
- mResultReceiver.send(Activity.RESULT_OK, bundle);
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
- }
+ intent.putExtras(bundle);
+ mParent.onActivityResult(DIALOG_CONFIRM_SYSTEM_DEFAULT, result, intent);
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE);
}
+ mShouldKeepDialog = false;
}
@VisibleForTesting
DialogContent getDialogContent() {
- DialogContent
- dialogContent = new DialogContent();
+ DialogContent dialogContent = new DialogContent();
switch (mDialogType) {
case DIALOG_CONFIRM_SYSTEM_DEFAULT:
dialogContent.mTitle = String.format(mContext.getString(
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index 2223db06562..edd302645e2 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,14 +16,11 @@
package com.android.settings.localepicker;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
-import android.os.Handler;
import android.os.LocaleList;
-import android.os.Looper;
-import android.os.ResultReceiver;
+import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -52,15 +49,20 @@ class LocaleDragAndDropAdapter
private static final String TAG = "LocaleDragAndDropAdapter";
private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
+ private static final String CFGKEY_DRAG_LOCALE = "dragLocales";
+ private static final String CFGKEY_DRAG_LOCALES_TO_POSITION = "dragLocales_end";
+
private final Context mContext;
+ private final ItemTouchHelper mItemTouchHelper;
+
private List mFeedItemList;
private List mCacheItemList;
- private final ItemTouchHelper mItemTouchHelper;
private RecyclerView mParentView = null;
private LocaleListEditor mParent;
private boolean mRemoveMode = false;
private boolean mDragEnabled = true;
private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
+ private LocaleStore.LocaleInfo mDragLocale;
class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener {
private final LocaleDragCell mLocaleDragCell;
@@ -87,8 +89,7 @@ class LocaleDragAndDropAdapter
}
}
- LocaleDragAndDropAdapter(LocaleListEditor parent,
- List feedItemList) {
+ LocaleDragAndDropAdapter(LocaleListEditor parent, List feedItemList) {
mFeedItemList = feedItemList;
mParent = parent;
mCacheItemList = new ArrayList<>(feedItemList);
@@ -202,6 +203,7 @@ class LocaleDragAndDropAdapter
final LocaleStore.LocaleInfo saved = mFeedItemList.get(fromPosition);
mFeedItemList.remove(fromPosition);
mFeedItemList.add(toPosition, saved);
+ mDragLocale = saved;
} else {
// TODO: It looks like sometimes the RecycleView tries to swap item -1
// I did not see it in a while, but if it happens, investigate and file a bug.
@@ -317,43 +319,20 @@ class LocaleDragAndDropAdapter
});
}
- public void doTheUpdateWithMovingLocaleItem() {
- LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
- final LocaleDialogFragment fragment = LocaleDialogFragment.newInstance();
- if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
- fragment.show(mParent,
- LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
- localeInfo,
- new ResultReceiver(new Handler(Looper.getMainLooper())) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- super.onReceiveResult(resultCode, resultData);
- int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
- if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
- if (resultCode == Activity.RESULT_OK) {
- doTheUpdate();
- if (!localeInfo.isTranslated()) {
- fragment.show(mParent,
- LocaleDialogFragment
- .DIALOG_NOT_AVAILABLE_LOCALE,
- localeInfo);
- }
- } else {
- if (!localeInfo.getLocale()
- .equals(mCacheItemList.get(0).getLocale())) {
- mFeedItemList = new ArrayList<>(mCacheItemList);
- notifyDataSetChanged();
- }
- }
- mCacheItemList = new ArrayList<>(mFeedItemList);
- }
- }
- });
- } else {
- doTheUpdate();
+ public void notifyListChanged(LocaleStore.LocaleInfo localeInfo) {
+ if (!localeInfo.getLocale().equals(mCacheItemList.get(0).getLocale())) {
+ mFeedItemList = new ArrayList<>(mCacheItemList);
+ notifyDataSetChanged();
}
}
+ public void setCacheItemList() {
+ mCacheItemList = new ArrayList<>(mFeedItemList);
+ }
+
+ public List getFeedItemList() {
+ return mFeedItemList;
+ }
private void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
@@ -373,6 +352,8 @@ class LocaleDragAndDropAdapter
}
}
outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales);
+ // Save the dragged locale before rotation
+ outInstanceState.putSerializable(CFGKEY_DRAG_LOCALE, mDragLocale);
}
}
@@ -381,18 +362,30 @@ class LocaleDragAndDropAdapter
* (for instance when the device is rotated)
*
* @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
+ * @param isDialogShowing A flag indicating whether the dialog is showing or not.
*/
- public void restoreState(Bundle savedInstanceState) {
- if (savedInstanceState != null && mRemoveMode) {
- final ArrayList selectedLocales =
- savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
- if (selectedLocales == null || selectedLocales.isEmpty()) {
- return;
+ public void restoreState(Bundle savedInstanceState, boolean isDialogShowing) {
+ if (savedInstanceState != null) {
+ if (mRemoveMode) {
+ final ArrayList selectedLocales =
+ savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
+ if (selectedLocales == null || selectedLocales.isEmpty()) {
+ return;
+ }
+ for (LocaleStore.LocaleInfo li : mFeedItemList) {
+ li.setChecked(selectedLocales.contains(li.getId()));
+ }
+ notifyItemRangeChanged(0, mFeedItemList.size());
+ } else if (isDialogShowing) {
+ // After rotation, the dragged position will be restored to original. Restore the
+ // drag locale's original position to the top.
+ mDragLocale = (LocaleStore.LocaleInfo) savedInstanceState.getSerializable(
+ CFGKEY_DRAG_LOCALE);
+ mFeedItemList.removeIf(
+ localeInfo -> TextUtils.equals(localeInfo.getId(), mDragLocale.getId()));
+ mFeedItemList.add(0, mDragLocale);
+ notifyItemRangeChanged(0, mFeedItemList.size());
}
- for (LocaleStore.LocaleInfo li : mFeedItemList) {
- li.setChecked(selectedLocales.contains(li.getId()));
- }
- notifyItemRangeChanged(0, mFeedItemList.size());
}
}
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 6317f24a304..7ec08f7300e 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -18,6 +18,8 @@ package com.android.settings.localepicker;
import static android.os.UserManager.DISALLOW_CONFIG_LOCALE;
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
+
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -32,12 +34,14 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
@@ -60,7 +64,7 @@ import java.util.Locale;
* Drag-and-drop editor for the user-ordered locale lists.
*/
@SearchIndexable
-public class LocaleListEditor extends RestrictedSettingsFragment {
+public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener {
protected static final String INTENT_LOCALE_KEY = "localeInfo";
private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
@@ -70,6 +74,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
private static final String KEY_LANGUAGES_PICKER = "languages_picker";
+ private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+ private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -80,6 +86,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
private LayoutPreference mLocalePickerPreference;
private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+ private FragmentManager mFragmentManager;
public LocaleListEditor() {
super(DISALLOW_CONFIG_LOCALE);
@@ -106,6 +113,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
LocaleStore.fillCache(this.getContext());
final List feedsList = getUserLocaleList();
mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
+ mFragmentManager = getChildFragmentManager();
}
@Override
@@ -141,7 +149,15 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false);
}
setRemoveMode(mRemoveMode);
- mAdapter.restoreState(savedInstanceState);
+
+ final LocaleDialogFragment dialogFragment =
+ (LocaleDialogFragment) mFragmentManager.findFragmentByTag(
+ TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ boolean isDialogShowing = false;
+ if (dialogFragment != null && dialogFragment.isAdded()) {
+ isDialogShowing = true;
+ }
+ mAdapter.restoreState(savedInstanceState, isDialogShowing);
if (mShowingRemoveDialog) {
showRemoveLocaleWarningDialog();
@@ -178,17 +194,32 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ LocaleStore.LocaleInfo localeInfo;
if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK
&& data != null) {
- final LocaleStore.LocaleInfo localeInfo =
- (LocaleStore.LocaleInfo) data.getSerializableExtra(
- INTENT_LOCALE_KEY);
-
+ localeInfo = (LocaleStore.LocaleInfo) data.getSerializableExtra(INTENT_LOCALE_KEY);
String preferencesTags = Settings.System.getString(
getContext().getContentResolver(), Settings.System.LOCALE_PREFERENCES);
mAdapter.addLocale(mayAppendUnicodeTags(localeInfo, preferencesTags));
updateVisibilityOfRemoveMenu();
+ } else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ localeInfo = mAdapter.getFeedItemList().get(0);
+ if (resultCode == Activity.RESULT_OK) {
+ mAdapter.doTheUpdate();
+ if (!localeInfo.isTranslated()) {
+ Bundle args = new Bundle();
+ args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE,
+ LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
+ args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+ LocaleDialogFragment localeDialogFragment = LocaleDialogFragment.newInstance();
+ localeDialogFragment.setArguments(args);
+ localeDialogFragment.show(mFragmentManager, TAG_DIALOG_NOT_AVAILABLE);
+ }
+ } else {
+ mAdapter.notifyListChanged(localeInfo);
+ }
+ mAdapter.setCacheItemList();
}
super.onActivityResult(requestCode, resultCode, data);
}
@@ -332,6 +363,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
list.setNestedScrollingEnabled(false);
mAdapter.setRecyclerView(list);
list.setAdapter(mAdapter);
+ list.setOnTouchListener(this);
mAddLanguage = layout.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@@ -348,6 +380,26 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
});
}
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP
+ || event.getAction() == MotionEvent.ACTION_CANCEL) {
+ LocaleStore.LocaleInfo localeInfo = mAdapter.getFeedItemList().get(0);
+ if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
+ final LocaleDialogFragment localeDialogFragment =
+ LocaleDialogFragment.newInstance();
+ Bundle args = new Bundle();
+ args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+ localeDialogFragment.setArguments(args);
+ localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ } else {
+ mAdapter.doTheUpdate();
+ }
+ }
+ return false;
+ }
+
// Hide the "Remove" menu if there is only one locale in the list, show it otherwise
// This is called when the menu is first created, and then one add / remove locale
private void updateVisibilityOfRemoveMenu() {
diff --git a/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java
index 5d469bf7f10..4a5f28b8855 100644
--- a/src/com/android/settings/localepicker/LocaleRecyclerView.java
+++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java
@@ -34,15 +34,4 @@ class LocaleRecyclerView extends RecyclerView {
public LocaleRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
-
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
- LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
- if (adapter != null) {
- adapter.doTheUpdateWithMovingLocaleItem();
- }
- }
- return super.onTouchEvent(e);
- }
}
diff --git a/src/com/android/settings/network/tether/TetherSettings.java b/src/com/android/settings/network/tether/TetherSettings.java
index ba19d1c129b..9fa8730cf10 100644
--- a/src/com/android/settings/network/tether/TetherSettings.java
+++ b/src/com/android/settings/network/tether/TetherSettings.java
@@ -171,6 +171,8 @@ public class TetherSettings extends RestrictedSettingsFragment
return;
}
+ setupTetherPreference();
+
final Activity activity = getActivity();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
@@ -184,7 +186,6 @@ public class TetherSettings extends RestrictedSettingsFragment
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
- setupTetherPreference();
setTopIntroPreferenceTitle();
mDataSaverBackend.addListener(this);
@@ -605,6 +606,7 @@ public class TetherSettings extends RestrictedSettingsFragment
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (mBluetoothPan.get() == null) {
mBluetoothPan.set((BluetoothPan) proxy);
+ updateBluetoothState();
}
}
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index df28304f738..eb10bd42be1 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -44,6 +44,7 @@ public class SlicePreferenceController extends BasePreferenceController implemen
LiveData mLiveData;
@VisibleForTesting
SlicePreference mSlicePreference;
+ private boolean mIsObservering = false;
private Uri mUri;
public SlicePreferenceController(Context context, String preferenceKey) {
@@ -68,25 +69,31 @@ public class SlicePreferenceController extends BasePreferenceController implemen
});
//TODO(b/120803703): figure out why we need to remove observer first
- mLiveData.removeObserver(this);
+ removeLiveDataObserver();
}
@Override
public void onStart() {
- if (mLiveData != null) {
+ if (mLiveData != null && !mIsObservering) {
+ mIsObservering = true;
mLiveData.observeForever(this);
}
}
@Override
public void onStop() {
- if (mLiveData != null) {
- mLiveData.removeObserver(this);
- }
+ removeLiveDataObserver();
}
@Override
public void onChanged(Slice slice) {
mSlicePreference.onSliceUpdated(slice);
}
+
+ private void removeLiveDataObserver() {
+ if (mLiveData != null && mIsObservering && mLiveData.hasActiveObservers()) {
+ mIsObservering = false;
+ mLiveData.removeObserver(this);
+ }
+ }
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index d904ed0f55c..28e02ec16e2 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -83,6 +82,7 @@ import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.users.CreateUserDialogController;
import com.android.settingslib.users.EditUserInfoController;
import com.android.settingslib.users.GrantAdminDialogController;
import com.android.settingslib.users.UserCreatingDialog;
@@ -119,6 +119,7 @@ public class UserSettings extends SettingsPreferenceFragment
/** UserId of the user being removed */
private static final String SAVE_REMOVING_USER = "removing_user";
+ private static final String SAVE_CREATE_USER = "create_user";
private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me";
@@ -171,9 +172,6 @@ public class UserSettings extends SettingsPreferenceFragment
static final int RESULT_GUEST_REMOVED = 100;
- private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
- "key_add_user_long_message_displayed";
-
private static final String KEY_TITLE = "title";
private static final String KEY_SUMMARY = "summary";
@@ -222,6 +220,8 @@ public class UserSettings extends SettingsPreferenceFragment
new GrantAdminDialogController();
private EditUserInfoController mEditUserInfoController =
new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY);
+ private CreateUserDialogController mCreateUserDialogController =
+ new CreateUserDialogController(Utils.FILE_PROVIDER_AUTHORITY);
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController;
private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController;
@@ -233,7 +233,7 @@ public class UserSettings extends SettingsPreferenceFragment
private CharSequence mPendingUserName;
private Drawable mPendingUserIcon;
- private boolean mGrantAdmin;
+ private boolean mPendingUserIsAdmin;
// A place to cache the generated default avatar
private Drawable mDefaultIconDrawable;
@@ -348,7 +348,11 @@ public class UserSettings extends SettingsPreferenceFragment
if (icicle.containsKey(SAVE_REMOVING_USER)) {
mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
}
- mEditUserInfoController.onRestoreInstanceState(icicle);
+ if (icicle.containsKey(SAVE_CREATE_USER)) {
+ mCreateUserDialogController.onRestoreInstanceState(icicle);
+ } else {
+ mEditUserInfoController.onRestoreInstanceState(icicle);
+ }
}
mUserCaps = UserCapabilities.create(activity);
@@ -440,7 +444,12 @@ public class UserSettings extends SettingsPreferenceFragment
@Override
public void onSaveInstanceState(Bundle outState) {
- mEditUserInfoController.onSaveInstanceState(outState);
+ if (mCreateUserDialogController.isActive()) {
+ outState.putBoolean(SAVE_CREATE_USER, mCreateUserDialogController.isActive());
+ mCreateUserDialogController.onSaveInstanceState(outState);
+ } else {
+ mEditUserInfoController.onSaveInstanceState(outState);
+ }
outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
super.onSaveInstanceState(outState);
}
@@ -448,6 +457,7 @@ public class UserSettings extends SettingsPreferenceFragment
@Override
public void startActivityForResult(Intent intent, int requestCode) {
mEditUserInfoController.startingActivityForResult();
+ mCreateUserDialogController.startingActivityForResult();
super.startActivityForResult(intent, requestCode);
}
@@ -562,6 +572,7 @@ public class UserSettings extends SettingsPreferenceFragment
&& resultCode == RESULT_GUEST_REMOVED) {
scheduleGuestCreation();
} else {
+ mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
}
}
@@ -704,37 +715,12 @@ public class UserSettings extends SettingsPreferenceFragment
.setPositiveButton(android.R.string.ok, null)
.create();
case DIALOG_ADD_USER: {
- final SharedPreferences preferences = getActivity().getPreferences(
- Context.MODE_PRIVATE);
- final boolean longMessageDisplayed = preferences.getBoolean(
- KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false);
- final int messageResId = longMessageDisplayed
- ? com.android.settingslib.R.string.user_add_user_message_short
- : com.android.settingslib.R.string.user_add_user_message_long;
- Dialog dlg = new AlertDialog.Builder(context)
- .setTitle(com.android.settingslib.R.string.user_add_user_title)
- .setMessage(messageResId)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- if (!longMessageDisplayed) {
- preferences.edit().putBoolean(
- KEY_ADD_USER_LONG_MESSAGE_DISPLAYED,
- true).apply();
- }
- if (UserManager.isMultipleAdminEnabled()) {
- showDialog(DIALOG_GRANT_ADMIN);
- } else {
- showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- return dlg;
- }
- case DIALOG_GRANT_ADMIN: {
- return buildGrantAdminDialog();
+ synchronized (mUserLock) {
+ mPendingUserName = getString(
+ com.android.settingslib.R.string.user_new_user_name);
+ mPendingUserIcon = null;
+ }
+ return buildAddUserDialog(USER_TYPE_USER);
}
case DIALOG_CHOOSE_USER_TYPE: {
List> data = new ArrayList>();
@@ -919,17 +905,14 @@ public class UserSettings extends SettingsPreferenceFragment
private Dialog buildAddUserDialog(int userType) {
Dialog d;
synchronized (mUserLock) {
- d = mEditUserInfoController.createDialog(
+ d = mCreateUserDialogController.createDialog(
getActivity(),
this::startActivityForResult,
- null,
- mPendingUserName.toString(),
- getString(userType == USER_TYPE_USER
- ? com.android.settingslib.R.string.user_info_settings_title
- : com.android.settingslib.R.string.profile_info_settings_title),
- (userName, userIcon) -> {
+ UserManager.isMultipleAdminEnabled(),
+ (userName, userIcon, isAdmin) -> {
mPendingUserIcon = userIcon;
mPendingUserName = userName;
+ mPendingUserIsAdmin = isAdmin;
addUserNow(userType);
},
() -> {
@@ -943,26 +926,6 @@ public class UserSettings extends SettingsPreferenceFragment
return d;
}
- private Dialog buildGrantAdminDialog() {
- return mGrantAdminDialogController.createDialog(
- getActivity(),
- (grantAdmin) -> {
- mGrantAdmin = grantAdmin;
- if (mGrantAdmin) {
- mMetricsFeatureProvider.action(getActivity(),
- SettingsEnums.ACTION_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
- } else {
- mMetricsFeatureProvider.action(getActivity(),
- SettingsEnums.ACTION_NOT_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
- }
- showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
- },
- () -> {
- mGrantAdmin = false;
- }
- );
- }
-
@Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
@@ -1065,7 +1028,7 @@ public class UserSettings extends SettingsPreferenceFragment
userName,
mUserManager.USER_TYPE_FULL_SECONDARY,
0);
- if (mGrantAdmin) {
+ if (mPendingUserIsAdmin) {
mUserManager.setUserAdmin(user.id);
}
} else {
@@ -1665,6 +1628,9 @@ public class UserSettings extends SettingsPreferenceFragment
synchronized (mUserLock) {
mRemovingUserId = -1;
updateUserList();
+ if (mCreateUserDialogController.isActive()) {
+ mCreateUserDialogController.clear();
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
index 5ee7ab3d13c..c68e90bdc17 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -24,25 +24,22 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settings.utils.ActivityControllerWrapper;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -55,11 +52,12 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
@@ -74,6 +72,9 @@ import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class AccessibilityHearingAidPreferenceControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2";
private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
@@ -82,7 +83,8 @@ public class AccessibilityHearingAidPreferenceControllerTest {
private BluetoothAdapter mBluetoothAdapter;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private BluetoothDevice mBluetoothDevice;
- private Activity mContext;
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
private Preference mHearingAidPreference;
private AccessibilityHearingAidPreferenceController mPreferenceController;
private ShadowApplication mShadowApplication;
@@ -106,11 +108,7 @@ public class AccessibilityHearingAidPreferenceControllerTest {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mShadowApplication = ShadowApplication.getInstance();
-
- mContext = spy((Activity) ActivityControllerWrapper.setup(
- Robolectric.buildActivity(Activity.class)).get());
setupEnvironment();
mHearingAidPreference = new Preference(mContext);
@@ -274,65 +272,6 @@ public class AccessibilityHearingAidPreferenceControllerTest {
verify(mPreferenceController).launchBluetoothDeviceDetailSetting(mCachedBluetoothDevice);
}
- @Test
- public void onSupportHearingAidProfile_isAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isTrue();
- }
-
- @Test
- public void onSupportHapClientProfile_isAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isTrue();
- }
-
- @Test
- public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isFalse();
- }
-
- @Test
- public void getConnectedHearingAidDevice_doNotReturnSubDevice() {
- when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
- when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(mBluetoothDevice))
- .thenReturn(true);
-
- assertThat(mPreferenceController.getConnectedHearingAidDevice()).isNull();
- }
-
- @Test
- @Config(shadows = ShadowAlertDialogCompat.class)
- public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
- final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
- when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidInfo.DeviceMode.MODE_BINAURAL);
- when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidInfo.DeviceSide.SIDE_LEFT);
- mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());
-
- mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
- BluetoothProfile.HEARING_AID);
-
- final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(dialog.isShowing()).isTrue();
- }
-
@Test
public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
new file mode 100644
index 00000000000..d16bc4351c3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link HearingAidAudioRoutingPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidAudioRoutingPreferenceControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ private HearingAidAudioRoutingPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mController = new HearingAidAudioRoutingPreferenceController(mContext, "test_key");
+ }
+
+ @Test
+ public void getAvailabilityStatus_audioRoutingNotSupported_returnUnsupported() {
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_audioRoutingNotSupported_available() {
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
new file mode 100644
index 00000000000..194b766dd75
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/** Tests for {@link HearingAidHelper}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
+public class HearingAidHelperTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+ @Mock
+ private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock
+ private CachedBluetoothDeviceManager mCachedDeviceManager;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private HapClientProfile mHapClientProfile;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+ private BluetoothAdapter mBluetoothAdapter;
+ private BluetoothDevice mBluetoothDevice;
+ private HearingAidHelper mHelper;
+
+ @Before
+ public void setUp() {
+ ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+ mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter);
+ mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+ when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+ when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+ when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+
+ mHelper = new HearingAidHelper(mContext);
+ }
+
+ @Test
+ public void isHearingAidSupported_supported_returnTrue() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+
+ assertThat(mHelper.isHearingAidSupported()).isTrue();
+ }
+
+ @Test
+ public void isHearingAidSupported_bluetoothOff_returnFalse() {
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ mBluetoothAdapter.disable();
+
+ assertThat(mHelper.isHearingAidSupported()).isFalse();
+ }
+
+
+ @Test
+ public void isAllHearingAidRelatedProfilesReady_allReady_returnTrue() {
+ when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+ when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+ assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isTrue();
+ }
+
+ @Test
+ public void isAllHearingAidRelatedProfilesReady_notFullReady_returnFalse() {
+ when(mHearingAidProfile.isProfileReady()).thenReturn(false);
+ when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+ assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isFalse();
+ }
+
+ @Test
+ public void getConnectedHearingAidDeviceList_oneDeviceAdded_getOneDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+
+ assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(1);
+ }
+
+ @Test
+ public void getConnectedHearingAidDeviceList_oneSubDeviceAdded_getZeroDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+ when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(
+ mBluetoothDevice)).thenReturn(true);
+
+ assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(0);
+ }
+
+ @Test
+ public void getConnectedHearingAidDevice_getExpectedCachedBluetoothDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+
+ assertThat(mHelper.getConnectedHearingAidDevice()).isEqualTo(mCachedBluetoothDevice);
+ assertThat(mCachedBluetoothDevice.getAddress()).isEqualTo(mBluetoothDevice.getAddress());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
similarity index 70%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
index 105da6546ad..4decf68d68c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,9 +38,15 @@ import androidx.preference.ListPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants;
import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import org.junit.Before;
import org.junit.Rule;
@@ -50,11 +57,13 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
import java.util.List;
/** Tests for {@link HearingDeviceAudioRoutingBasePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
@Rule
@@ -63,8 +72,14 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
- private static final String FAKE_KEY = "fake_key";
+ private final ListPreference mListPreference = new ListPreference(mContext);
+ @Mock
+ private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock
+ private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock
private AudioProductStrategy mAudioProductStrategyMedia;
@Mock
@@ -72,8 +87,10 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
@Mock
private BluetoothDevice mBluetoothDevice;
@Spy
- private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext);
- private final ListPreference mListPreference = new ListPreference(mContext);
+ private HearingAidAudioRoutingHelper mAudioRoutingHelper =
+ new HearingAidAudioRoutingHelper(mContext);
+ @Mock
+ private HearingAidHelper mHearingAidHelper;
private TestHearingDeviceAudioRoutingBasePreferenceController mController;
@Before
@@ -83,19 +100,23 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
AudioDeviceInfo.TYPE_HEARING_AID,
TEST_DEVICE_ADDRESS);
+ ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+ mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(TEST_DEVICE_ADDRESS);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
- when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(hearingDeviceAttribute);
+ doReturn(hearingDeviceAttribute).when(
+ mAudioRoutingHelper).getMatchedHearingDeviceAttributes(any());
when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType(
- AudioManager.STREAM_MUSIC))
- .thenReturn((new AudioAttributes.Builder()).build());
- when(mHelper.getAudioProductStrategies()).thenReturn(List.of(mAudioProductStrategyMedia));
+ AudioManager.STREAM_MUSIC)).thenReturn((new AudioAttributes.Builder()).build());
+ when(mAudioRoutingHelper.getAudioProductStrategies()).thenReturn(
+ List.of(mAudioProductStrategyMedia));
- mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, FAKE_KEY,
- mHelper);
- TestHearingDeviceAudioRoutingBasePreferenceController.setupForTesting(
- mCachedBluetoothDevice);
+ mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext,
+ "test_key",
+ mAudioRoutingHelper, mHearingAidHelper);
mListPreference.setEntries(R.array.bluetooth_audio_routing_titles);
mListPreference.setEntryValues(R.array.bluetooth_audio_routing_values);
mListPreference.setSummary("%s");
@@ -122,20 +143,21 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
@Test
public void onPreferenceChange_noMatchedDeviceAttributes_notCallSetStrategies() {
- when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
+ when(mAudioRoutingHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
- verify(mHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), anyInt());
+ verify(mAudioRoutingHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(),
+ anyInt());
}
private static class TestHearingDeviceAudioRoutingBasePreferenceController extends
HearingDeviceAudioRoutingBasePreferenceController {
- private static CachedBluetoothDevice sCachedBluetoothDevice;
private static int sSavedRoutingValue;
TestHearingDeviceAudioRoutingBasePreferenceController(Context context,
- String preferenceKey, HearingAidAudioRoutingHelper helper) {
- super(context, preferenceKey, helper);
+ String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+ HearingAidHelper hearingAidHelper) {
+ super(context, preferenceKey, audioRoutingHelper, hearingAidHelper);
}
@Override
@@ -143,11 +165,6 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
return new int[]{AudioAttributes.USAGE_MEDIA};
}
- @Override
- protected CachedBluetoothDevice getHearingDevice() {
- return sCachedBluetoothDevice;
- }
-
@Override
protected void saveRoutingValue(Context context, int routingValue) {
sSavedRoutingValue = routingValue;
@@ -157,9 +174,5 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
protected int restoreRoutingValue(Context context) {
return sSavedRoutingValue;
}
-
- public static void setupForTesting(CachedBluetoothDevice cachedBluetoothDevice) {
- sCachedBluetoothDevice = cachedBluetoothDevice;
- }
}
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
similarity index 98%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
index dec4cc4bb01..8eed2940984 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
diff --git a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
index c8606e134a5..bc65563650f 100644
--- a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
@@ -20,13 +20,19 @@ import static android.provider.Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SE
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.Before;
@@ -35,39 +41,51 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class ContactSearchPreferenceControllerTest {
private static final String PREF_KEY = "contacts_search";
-
- @Mock
- private UserHandle mManagedUser;
+ private static final int MANAGED_USER_ID = 10;
private Context mContext;
private ContactSearchPreferenceController mController;
private RestrictedSwitchPreference mPreference;
+ @Mock
+ private UserHandle mManagedUser;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private UserInfo mUserInfo;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
- mController.setManagedUser(mManagedUser);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPreference = spy(new RestrictedSwitchPreference(mContext));
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+ mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
- mController.setManagedUser(null);
+ when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+ mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
+
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
- mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@@ -75,32 +93,96 @@ public class ContactSearchPreferenceControllerTest {
@Test
public void updateState_shouldRefreshContent() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isFalse();
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier());
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void updateState_preferenceShouldBeDisabled() {
mController.updateState(mPreference);
+
verify(mPreference).setDisabledByAdmin(any());
}
@Test
public void onPreferenceChange_shouldUpdateProviderValue() {
mController.onPreferenceChange(mPreference, false);
+
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier()))
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID))
.isEqualTo(0);
mController.onPreferenceChange(mPreference, true);
+
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier()))
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID))
.isEqualTo(1);
}
-}
\ No newline at end of file
+
+ @Test
+ public void onQuietModeDisabled_preferenceEnabled() {
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onQuietModeEnabled_preferenceDisabledAndUnchecked() {
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void afterQuietModeTurnedOnAndOffWhenPreferenceChecked_toggleCheckedAndEnabled() {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void afterQuietModeTurnedOnAndOffWhenPreferenceUnchecked_toggleUncheckedAndEnabled() {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
new file mode 100644
index 00000000000..2698efa4bd8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.accounts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Collections;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class ManagedProfileQuietModeEnablerTest {
+ private static final int MANAGED_USER_ID = 10;
+ private Context mContext;
+ private ManagedProfileQuietModeEnabler mQuietModeEnabler;
+ private LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
+ public LifecycleRegistry registry = new LifecycleRegistry(this);
+
+ @Override
+ public Lifecycle getLifecycle() {
+ return registry;
+ }
+ };
+
+ @Mock
+ private ManagedProfileQuietModeEnabler.QuietModeChangeListener mOnQuietModeChangeListener;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private UserHandle mManagedUser;
+ @Mock
+ private UserInfo mUserInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(mContext,
+ mOnQuietModeChangeListener);
+ }
+
+ @Test
+ public void onSetQuietMode_shouldRequestQuietModeEnabled() {
+ mQuietModeEnabler.setQuietModeEnabled(false);
+ verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
+ mQuietModeEnabler.setQuietModeEnabled(true);
+ verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
+ }
+
+ @Test
+ public void onIsQuietModeEnabled_shouldCallIsQuietModeEnabled() {
+ assertThat(mQuietModeEnabler.isQuietModeEnabled()).isEqualTo(
+ verify(mUserManager).isQuietModeEnabled(any()));
+ }
+
+ @Test
+ public void onQuietModeChanged_listenerNotified() {
+ mQuietModeEnabler.onStart(mLifecycleOwner);
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE).putExtra(
+ Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE).putExtra(
+ Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+ verify(mOnQuietModeChangeListener, times(2)).onQuietModeChanged();
+ }
+
+ @Test
+ public void onStart_shouldRegisterReceiver() {
+ mQuietModeEnabler.onStart(mLifecycleOwner);
+ verify(mContext).registerReceiver(eq(mQuietModeEnabler.mReceiver), any(), anyInt());
+ }
+
+ @Test
+ public void onStop_shouldUnregisterReceiver() {
+ // register it first
+ mContext.registerReceiver(mQuietModeEnabler.mReceiver, null,
+ Context.RECEIVER_EXPORTED/*UNAUDITED*/);
+
+ mQuietModeEnabler.onStop(mLifecycleOwner);
+ verify(mContext).unregisterReceiver(mQuietModeEnabler.mReceiver);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
index 2a283181b1c..e862d108c7c 100644
--- a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
@@ -19,18 +19,18 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
-import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
-import com.android.settings.R;
+import com.android.settingslib.widget.MainSwitchPreference;
import org.junit.Before;
import org.junit.Test;
@@ -38,43 +38,51 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class WorkModePreferenceControllerTest {
private static final String PREF_KEY = "work_mode";
+ private static final int MANAGED_USER_ID = 10;
+
+ private Context mContext;
+ private WorkModePreferenceController mController;
+ private MainSwitchPreference mPreference;
@Mock
private UserManager mUserManager;
@Mock
private UserHandle mManagedUser;
-
- private Context mContext;
- private WorkModePreferenceController mController;
- private SwitchPreference mPreference;
+ @Mock
+ private UserInfo mUserInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
-
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ mPreference = new MainSwitchPreference(mContext);
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
mController = new WorkModePreferenceController(mContext, PREF_KEY);
- mController.setManagedUser(mManagedUser);
- mPreference = new SwitchPreference(mContext);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
- mController.setManagedUser(null);
+ when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+ mController = new WorkModePreferenceController(mContext, PREF_KEY);
+
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(WorkModePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
- mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(WorkModePreferenceController.AVAILABLE);
}
@@ -83,41 +91,29 @@ public class WorkModePreferenceControllerTest {
public void updateState_shouldRefreshContent() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(false);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isTrue();
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getText(R.string.work_mode_on_summary));
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(true);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isFalse();
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getText(R.string.work_mode_off_summary));
}
@Test
public void onPreferenceChange_shouldRequestQuietModeEnabled() {
+ mController.setPreference(mPreference);
+
mController.onPreferenceChange(mPreference, true);
+
verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
mController.onPreferenceChange(mPreference, false);
+
verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
}
-
- @Test
- public void onStart_shouldRegisterReceiver() {
- mController.onStart();
- verify(mContext).registerReceiver(eq(mController.mReceiver), any(), anyInt());
- }
-
- @Test
- public void onStop_shouldUnregisterReceiver() {
- // register it first
- mContext.registerReceiver(mController.mReceiver, null,
- Context.RECEIVER_EXPORTED/*UNAUDITED*/);
-
- mController.onStop();
- verify(mContext).unregisterReceiver(mController.mReceiver);
- }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 7282be357c1..959c6426894 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -53,7 +53,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Vibrator;
-import android.util.FeatureFlagUtils;
import android.view.Display;
import android.view.Surface;
import android.view.View;
@@ -203,8 +202,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayPortrait() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
@@ -216,8 +213,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayLandscape() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
@@ -229,8 +224,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void fingerprintUdfpsOverlayEnrollment_usesCorrectProgressBarFillColor() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
final TypedArray ta = mActivity.obtainStyledAttributes(null,
R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
@@ -250,9 +243,7 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void fingerprintUdfpsOverlayEnrollment_checkViewOverlapPortrait() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
- when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
final GlifLayout defaultLayout = mActivity.findViewById(R.id.setup_wizard_layout);
@@ -294,9 +285,9 @@ public class FingerprintEnrollEnrollingTest {
udfpsEnrollView.getViewTreeObserver().addOnDrawListener(() -> {
udfpsEnrollView.getLocationOnScreen(udfpsEnrollViewPosition);
rectUdfpsEnrollView.set(new Rect(udfpsEnrollViewPosition[0],
- udfpsEnrollViewPosition[1], udfpsEnrollViewPosition[0]
- + udfpsEnrollView.getWidth(), udfpsEnrollViewPosition[1]
- + udfpsEnrollView.getHeight()));
+ udfpsEnrollViewPosition[1], udfpsEnrollViewPosition[0]
+ + udfpsEnrollView.getWidth(), udfpsEnrollViewPosition[1]
+ + udfpsEnrollView.getHeight()));
});
lottieAnimationContainer.getViewTreeObserver().addOnDrawListener(() -> {
@@ -320,10 +311,36 @@ public class FingerprintEnrollEnrollingTest {
.intersect(rectUdfpsEnrollView.get())).isFalse();
}
+ @Test
+ public void fingerprintUdfpsOverlayEnrollment_descriptionViewGoneWithOverlap() {
+ initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
+ doReturn(true).when(mActivity).hasOverlap(any(), any());
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
+ createActivity();
+
+ final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
+ final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
+
+ defaultLayout.getViewTreeObserver().dispatchOnDraw();
+ assertThat(descriptionTextView.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void fingerprintUdfpsOverlayEnrollment_descriptionViewVisibleWithoutOverlap() {
+ initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
+ doReturn(false).when(mActivity).hasOverlap(any(), any());
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
+ createActivity();
+
+ final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
+ final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
+
+ defaultLayout.getViewTreeObserver().dispatchOnDraw();
+ assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
@Test
public void forwardEnrollProgressEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -337,8 +354,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void forwardEnrollHelpEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -352,8 +367,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void forwardEnrollAcquiredEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -368,8 +381,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void forwardEnrollPointerDownEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -383,8 +394,6 @@ public class FingerprintEnrollEnrollingTest {
@Test
public void forwardEnrollPointerUpEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index 2bc81e60a06..18b05add7ad 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -20,8 +20,11 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.ADD_FINGERPRINT_REQUEST;
+import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.CHOOSE_LOCK_GENERIC_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_FINGERPRINT_ADD;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -54,6 +57,7 @@ import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -63,6 +67,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -74,7 +79,7 @@ import java.util.ArrayList;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowSettingsPreferenceFragment.class, ShadowUtils.class, ShadowFragment.class,
- ShadowUserManager.class})
+ ShadowUserManager.class, ShadowLockPatternUtils.class})
public class FingerprintSettingsFragmentTest {
private FingerprintSettingsFragment mFragment;
private Context mContext;
@@ -92,10 +97,62 @@ public class FingerprintSettingsFragmentTest {
doReturn(true).when(mFingerprintManager).isHardwareDetected();
ShadowUtils.setFingerprintManager(mFingerprintManager);
FakeFeatureFactory.setupForTest();
+ }
+ @After
+ public void tearDown() {
+ ShadowUtils.reset();
+ }
+
+ @Test
+ public void testAddFingerprint_inFullScreen_noDialog() {
+ setUpFragment(false);
+ // Click "Add Fingerprint"
+ final Preference preference = new Preference(mContext);
+ preference.setKey(KEY_FINGERPRINT_ADD);
+ mFragment.onPreferenceTreeClick(preference);
+
+ verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
+ verify(mFragmentTransaction, never()).add(any(),
+ eq(BiometricsSplitScreenDialog.class.getName()));
+
+ }
+
+ @Test
+ public void testAddFingerprint_inMultiWindow_showsDialog() {
+ setUpFragment(false);
+
+ doReturn(true).when(mActivity).isInMultiWindowMode();
+
+ // Click "Add Fingerprint"
+ final Preference preference = new Preference(mContext);
+ preference.setKey(KEY_FINGERPRINT_ADD);
+ mFragment.onPreferenceTreeClick(preference);
+
+ verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
+ verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
+ }
+
+ @Test
+ public void testChooseLockKeyForFingerprint() {
+ setUpFragment(true);
+ ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(
+ Intent.class);
+ verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(),
+ eq(CHOOSE_LOCK_GENERIC_REQUEST));
+
+ Intent intent = intentArgumentCaptor.getValue();
+ assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
+ false)).isTrue();
+ }
+
+ private void setUpFragment(boolean showChooseLock) {
Intent intent = new Intent();
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L);
+ if (!showChooseLock) {
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L);
+ }
+
mActivity = spy(Robolectric.buildActivity(FragmentActivity.class, intent).get());
mContext = spy(ApplicationProvider.getApplicationContext());
@@ -112,49 +169,12 @@ public class FingerprintSettingsFragmentTest {
doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
setSensor();
- }
- @After
- public void tearDown() {
- ShadowUtils.reset();
- }
-
- @Test
- public void testAddFingerprint_inFullScreen_noDialog() {
// Start fragment
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume();
-
- // Click "Add Fingerprint"
- final Preference preference = new Preference(mContext);
- preference.setKey(KEY_FINGERPRINT_ADD);
- mFragment.onPreferenceTreeClick(preference);
-
- verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
- verify(mFragmentTransaction, never()).add(any(),
- eq(BiometricsSplitScreenDialog.class.getName()));
-
- }
-
- @Test
- public void testAddFingerprint_inMultiWindow_showsDialog() {
- // Start fragment
- mFragment.onAttach(mContext);
- mFragment.onCreate(null);
- mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
- mFragment.onResume();
-
- doReturn(true).when(mActivity).isInMultiWindowMode();
-
- // Click "Add Fingerprint"
- final Preference preference = new Preference(mContext);
- preference.setKey(KEY_FINGERPRINT_ADD);
- mFragment.onPreferenceTreeClick(preference);
-
- verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
- verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
}
private void setSensor() {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
deleted file mode 100644
index ea65856de61..00000000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDetailsAudioRoutingController.KEY_AUDIO_ROUTING;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.util.FeatureFlagUtils;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingController}. */
-@RunWith(RobolectricTestRunner.class)
-public class BluetoothDetailsAudioRoutingControllerTest extends
- BluetoothDetailsControllerTestBase {
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
- private BluetoothDetailsAudioRoutingController mController;
-
- @Override
- public void setUp() {
- super.setUp();
-
- mController = new BluetoothDetailsAudioRoutingController(mContext, mFragment, mCachedDevice,
- mLifecycle);
- final PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
- preferenceCategory.setKey(mController.getPreferenceKey());
- mScreen.addPreference(preferenceCategory);
- }
-
- @Test
- public void isAvailable_isHearingAidDevice_available() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
- when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
-
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_isNotHearingAidDevice_notAvailable() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
- when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void init_isHearingAidDevice_expectedAudioRoutingPreference() {
- when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
-
- mController.init(mScreen);
- final Preference preference = mScreen.findPreference(KEY_AUDIO_ROUTING);
- final String address = preference.getExtras().getString(
- BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS);
- final String fragment = preference.getFragment();
-
- assertThat(address).isEqualTo(TEST_ADDRESS);
- assertThat(fragment).isEqualTo(BluetoothDetailsAudioRoutingFragment.class.getName());
-
- }
-}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
deleted file mode 100644
index 9bd4f1b8d84..00000000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
+++ /dev/null
@@ -1,96 +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.bluetooth;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingFragment}. */
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothUtils.class})
-public class BluetoothDetailsAudioRoutingFragmentTest {
-
- @Rule
- public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
- private final Context mContext = ApplicationProvider.getApplicationContext();
-
- private BluetoothDetailsAudioRoutingFragment mFragment;
- @Mock
- private LocalBluetoothManager mLocalBluetoothManager;
- @Mock
- private CachedBluetoothDeviceManager mCachedDeviceManager;
- @Mock
- private LocalBluetoothAdapter mLocalBluetoothAdapter;
- @Mock
- private BluetoothDevice mBluetoothDevice;
- @Mock
- private CachedBluetoothDevice mCachedDevice;
-
- @Before
- public void setUp() {
- setupEnvironment();
-
- when(mLocalBluetoothAdapter.getRemoteDevice(TEST_ADDRESS)).thenReturn(mBluetoothDevice);
- when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
- when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice);
-
- mFragment = new BluetoothDetailsAudioRoutingFragment();
- }
-
- @Test
- public void onAttach_setArgumentsWithAddress_expectedCachedDeviceWithAddress() {
- final Bundle args = new Bundle();
- args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS);
- mFragment.setArguments(args);
-
- mFragment.onAttach(mContext);
-
- assertThat(mFragment.mCachedDevice.getAddress()).isEqualTo(TEST_ADDRESS);
- }
-
- private void setupEnvironment() {
- ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
- when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
- when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
index 314f8c38091..de380c40c8e 100644
--- a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
@@ -81,9 +81,10 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(true).
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
+
+ // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
+ // on a device/emulator, please refer to
+ // GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.onPreferenceChange(mPreference, true);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -97,9 +98,10 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(false).
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
+
+ // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
+ // on a device/emulator, please refer to
+ // GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.onPreferenceChange(mPreference, false);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -124,20 +126,14 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
@Test
public void updateState_angleSupported_angleUsed_preferenceShouldBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference);
- verify(mPreference).setChecked(true); //false
+ verify(mPreference).setChecked(true);
}
@Test
public void updateState_angleSupported_angleNotUsed_preferenceShouldNotBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver(false)
- // works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index eb4b598823f..ded108cfc89 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -43,7 +43,6 @@ import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.UsageView;
-import com.android.settingslib.R;
import com.android.settingslib.fuelgauge.Estimate;
import org.junit.Before;
@@ -163,26 +162,6 @@ public class BatteryInfoTest {
assertThat(info2.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX);
}
- @Test
- public void testGetBatteryInfo_basedOnUsageTrueLessThanSevenMinutes_usesCorrectString() {
- Estimate estimate = new Estimate(Duration.ofMinutes(7).toMillis(),
- true /* isBasedOnUsage */,
- 1000 /* averageDischargeTime */);
- BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- false /* shortString */);
- BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- true /* shortString */);
-
- // These should be identical in either case
- assertThat(info.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
- assertThat(info2.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
- assertThat(info2.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX);
- }
-
@Test
@Ignore
public void getBatteryInfo_MoreThanOneDay_suggestionLabelIsCorrectString() {
@@ -196,25 +175,6 @@ public class BatteryInfoTest {
assertThat(info.suggestionLabel).doesNotContain(BATTERY_RUN_OUT_PREFIX);
}
- @Test
- public void
- testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() {
- Estimate estimate = new Estimate(Duration.ofMinutes(10).toMillis(),
- true /* isBasedOnUsage */,
- 1000 /* averageDischargeTime */);
- BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- false /* shortString */);
-
- // Check that strings are showing less than 15 minutes remaining regardless of exact time.
- assertThat(info.chargeLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_less_than_duration,
- FIFTEEN_MIN_FORMATTED, TEST_BATTERY_LEVEL_10));
- assertThat(info.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_less_than_duration_only,
- FIFTEEN_MIN_FORMATTED));
- }
-
@Test
public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() {
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
index 111ee5a7571..16d51beca64 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
@@ -18,19 +18,32 @@ package com.android.settings.localepicker;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Activity;
+import android.app.IActivityManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import org.junit.After;
@@ -45,22 +58,42 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@Config(shadows = {ShadowAlertDialogCompat.class, ShadowActivityManager.class})
public class LocaleListEditorTest {
+ private static final String ARG_DIALOG_TYPE = "arg_dialog_type";
+ private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+ private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
+ private static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+ private static final int REQUEST_CONFIRM_SYSTEM_DEFAULT = 1;
+
private LocaleListEditor mLocaleListEditor;
private Context mContext;
private FragmentActivity mActivity;
+ private List mLocaleList;
+ private Intent mIntent = new Intent();
@Mock
private LocaleDragAndDropAdapter mAdapter;
+ @Mock
+ private LocaleStore.LocaleInfo mLocaleInfo;
+ @Mock
+ private FragmentManager mFragmentManager;
+ @Mock
+ private FragmentTransaction mFragmentTransaction;
+ @Mock
+ private View mView;
+ @Mock
+ private IActivityManager mActivityService;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mLocaleListEditor = spy(new LocaleListEditor());
@@ -74,6 +107,8 @@ public class LocaleListEditorTest {
ReflectionHelpers.setField(mLocaleListEditor, "mUserManager",
RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE));
ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter);
+ ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager);
+ when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
FakeFeatureFactory.setupForTest();
}
@@ -174,4 +209,65 @@ public class LocaleListEditorTest {
assertThat(result.getLocale().getUnicodeLocaleType("fw")).isEqualTo("wed");
assertThat(result.getLocale().getUnicodeLocaleType("mu")).isEqualTo("celsius");
}
+
+ @Test
+ public void onActivityResult_ResultCodeIsOk_showNotAvailableDialog() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ mIntent.putExtras(bundle);
+ setUpLocaleConditions();
+ mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_OK,
+ mIntent);
+
+ verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+ eq(TAG_DIALOG_NOT_AVAILABLE));
+ }
+
+ @Test
+ public void onActivityResult_ResultCodeIsCancel_notifyAdapterListChanged() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ mIntent.putExtras(bundle);
+ setUpLocaleConditions();
+ mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_CANCELED,
+ mIntent);
+
+ verify(mAdapter).notifyListChanged(mLocaleInfo);
+ }
+
+ @Test
+ public void onTouch_dragDifferentLocaleToTop_showConfirmDialog() throws Exception {
+ MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ setUpLocaleConditions();
+ final Configuration config = new Configuration();
+ config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US")));
+ when(mActivityService.getConfiguration()).thenReturn(config);
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ mLocaleListEditor.onTouch(mView, event);
+
+ verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+ eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT));
+ }
+
+ @Test
+ public void onTouch_dragSameLocaleToTop_updateAdapter() throws Exception {
+ MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ setUpLocaleConditions();
+ final Configuration config = new Configuration();
+ config.setLocales((LocaleList.forLanguageTags("en-US,zh-TW")));
+ when(mActivityService.getConfiguration()).thenReturn(config);
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ mLocaleListEditor.onTouch(mView, event);
+
+ verify(mAdapter).doTheUpdate();
+ }
+
+ private void setUpLocaleConditions() {
+ ShadowActivityManager.setService(mActivityService);
+ mLocaleList = new ArrayList<>();
+ mLocaleList.add(mLocaleInfo);
+ when(mLocaleInfo.getFullNameNative()).thenReturn("English");
+ when(mLocaleInfo.getLocale()).thenReturn(LocaleList.forLanguageTags("en-US").get(0));
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 5310ae09801..8d6d2d9bc4e 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -133,18 +133,12 @@ public class MobileNetworkSummaryControllerTest {
assertThat(mController.isAvailable()).isFalse();
}
- @Ignore
@Test
- public void getSummary_noSubscriptions_correctSummaryAndClickHandler() {
+ public void getSummary_noSubscriptions_returnSummaryCorrectly() {
mController.displayPreference(mPreferenceScreen);
mController.onResume();
- assertThat(mController.getSummary()).isEqualTo("Add a network");
- final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class);
- doNothing().when(mContext).startActivity(intentCaptor.capture());
- mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
+ assertThat(mController.getSummary()).isEqualTo("Add a network");
}
@Test
@@ -300,15 +294,13 @@ public class MobileNetworkSummaryControllerTest {
assertThat(captor.getValue()).isFalse();
}
- @Ignore
@Test
- public void onResume_noSubscriptionEsimDisabled_isDisabled() {
+ public void onAvailableSubInfoChanged_noSubscriptionEsimDisabled_isDisabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
- SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
when(mEuiccManager.isEnabled()).thenReturn(false);
mController.displayPreference(mPreferenceScreen);
- mController.onResume();
+ mController.onAvailableSubInfoChanged(null);
assertThat(mPreference.isEnabled()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index dbc60dce731..12a540d7c33 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -30,6 +30,8 @@ import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericF
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -126,7 +128,9 @@ public class ChooseLockGenericTest {
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
- false);
+ true);
+ ShadowUtils.setFingerprintManager(mFingerprintManager);
+ ShadowUtils.setFaceManager(mFaceManager);
}
@After
@@ -540,35 +544,63 @@ public class ChooseLockGenericTest {
@Test
public void updatePreferenceText_supportBiometrics_showFaceAndFingerprint() {
- ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
- final PasswordPolicy policy = new PasswordPolicy();
- policy.quality = PASSWORD_QUALITY_ALPHABETIC;
- ShadowLockPatternUtils.setRequestedProfilePasswordMetrics(policy.getMinMetrics());
-
+ ShadowStorageManager.setIsFileEncrypted(false);
final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_BIOMETRICS, true);
initActivity(intent);
- final Intent passwordIntent = mFragment.getLockPatternIntent();
- assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY,
- PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW);
final String supportFingerprint = capitalize(mActivity.getResources().getString(
R.string.security_settings_fingerprint));
final String supportFace = capitalize(mActivity.getResources().getString(
R.string.keywords_face_settings));
+ String pinTitle =
+ (String) mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle();
+ String patternTitle =
+ (String) mFragment.findPreference(ScreenLockType.PATTERN.preferenceKey).getTitle();
+ String passwordTitle =
+ (String) mFragment.findPreference(ScreenLockType.PASSWORD.preferenceKey).getTitle();
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
- supportFace);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
- supportFace);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
- supportFace);
+ assertThat(pinTitle).contains(supportFingerprint);
+ assertThat(pinTitle).contains(supportFace);
+ assertThat(patternTitle).contains(supportFingerprint);
+ assertThat(patternTitle).contains(supportFace);
+ assertThat(passwordTitle).contains(supportFingerprint);
+ assertThat(passwordTitle).contains(supportFace);
+ }
+
+ @Test
+ public void updatePreferenceText_supportFingerprint_showFingerprint() {
+ ShadowStorageManager.setIsFileEncrypted(false);
+ final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FINGERPRINT, true);
+ initActivity(intent);
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+
+ assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_pin));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_pattern));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_password));
+ }
+
+ @Test
+ public void updatePreferenceText_supportFace_showFace() {
+
+ ShadowStorageManager.setIsFileEncrypted(false);
+ final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FACE, true);
+ initActivity(intent);
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+
+ assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_pin));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_pattern));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_password));
}
private void initActivity(@Nullable Intent intent) {
diff --git a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
index 65eaddd50ab..e8bd27d97e6 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
@@ -18,8 +18,10 @@ package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.Uri;
@@ -43,11 +45,11 @@ public class SlicePreferenceControllerTest {
private LiveData mLiveData;
@Mock
private SlicePreference mSlicePreference;
+
private Context mContext;
private SlicePreferenceController mController;
private Uri mUri;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -78,10 +80,30 @@ public class SlicePreferenceControllerTest {
@Test
public void onStop_unregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(true);
+ mController.onStart();
+
mController.onStop();
verify(mLiveData).removeObserver(mController);
}
+ @Test
+ public void onStop_noActiveObservers_notUnregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(false);
+ mController.onStart();
+
+ mController.onStop();
+ verify(mLiveData, never()).removeObserver(mController);
+ }
+
+ @Test
+ public void onStop_notRegisterObserver_notUnregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(true);
+
+ mController.onStop();
+ verify(mLiveData, never()).removeObserver(mController);
+ }
+
@Test
public void onChanged_nullSlice_updateSlice() {
mController.onChanged(null);
diff --git a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
new file mode 100644
index 00000000000..3f85535df53
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
@@ -0,0 +1,325 @@
+/*
+ * 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.development.graphicsdriver;
+
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.ANGLE_DRIVER_SUFFIX;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.Injector;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_PERSISTENT_GRAPHICS_EGL;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_RO_GFX_ANGLE_SUPPORTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.SystemProperties;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.development.DevelopmentSettingsDashboardFragment;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
+ private Context mContext;
+ private SwitchPreference mPreference;
+
+ private GraphicsDriverEnableAngleAsSystemDriverController mController;
+
+ @Mock
+ private DevelopmentSettingsDashboardFragment mFragment;
+
+ @Mock
+ private GraphicsDriverSystemPropertiesWrapper mSystemPropertiesMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mContext = ApplicationProvider.getApplicationContext();
+
+ // Construct a GraphicsDriverEnableAngleAsSystemDriverController with two Overrides:
+ // 1) Override the mSystemProperties with mSystemPropertiesMock,
+ // so we can force the SystemProperties with values we need to run tests.
+ // 2) Override the showRebootDialog() to do nothing.
+ // We do not need to pop up the reboot dialog in the test.
+ mController = new GraphicsDriverEnableAngleAsSystemDriverController(
+ mContext, mFragment, new Injector(){
+ @Override
+ public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+ }) {
+ @Override
+ void showRebootDialog() {
+ // do nothing
+ }
+ };
+
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference = new SwitchPreference(mContext);
+ mPreference.setKey(mController.getPreferenceKey());
+ screen.addPreference(mPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void onPreferenceChange_switchOn_shouldEnableAngleAsSystemDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test onPreferenceChange(true) updates the persist.graphics.egl to "angle"
+ mController.onPreferenceChange(mPreference, true);
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onPreferenceChange_switchOff_shouldDisableAngleAsSystemDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test onPreferenceChange(false) updates the persist.graphics.egl to ""
+ mController.onPreferenceChange(mPreference, false);
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void updateState_angleNotSupported_PreferenceShouldDisabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void updateState_angleNotSupported_PreferenceShouldNotBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void updateState_angleSupported_PreferenceShouldEnabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_angleSupported_angleIsSystemGLESDriver_PreferenceShouldBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn(ANGLE_DRIVER_SUFFIX);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void
+ updateState_angleSupported_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchEnabled_angleSupported_PreferenceShouldEnabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ mController.onDeveloperOptionsSwitchEnabled();
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchEnabled_angleNotSupported_PrefenceShouldDisabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("false");
+ mController.onDeveloperOptionsSwitchEnabled();
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_angleIsNotSystemGLESDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that onDeveloperOptionSwitchDisabled,
+ // persist.graphics.egl updates to ""
+ mController.onDeveloperOptionsSwitchDisabled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_PreferenceShouldNotBeChecked() {
+ mController.onDeveloperOptionsSwitchDisabled();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_PreferenceShouldDisabled() {
+ mController.onDeveloperOptionsSwitchDisabled();
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onRebootCancelled_ToggleSwitchFromOnToOff() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that if the current persist.graphics.egl is "angle",
+ // when reboot is cancelled, persist.graphics.egl is changed back to "",
+ // and switch is set to unchecked.
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn(ANGLE_DRIVER_SUFFIX);
+ mController.onRebootCancelled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+ assertThat(mPreference.isChecked()).isFalse();
+
+ // Done with the test, remove the callback.
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onRebootCancelled_ToggleSwitchFromOffToOn() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that if the current persist.graphics.egl is "",
+ // when reboot is cancelled, persist.graphics.egl is changed back to "angle",
+ // and switch is set to checked.
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn("");
+ mController.onRebootCancelled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
+ assertThat(mPreference.isChecked()).isTrue();
+
+ // Done with the test, remove the callback.
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+}
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
index b0998c023a6..824954da52d 100644
--- a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -17,8 +17,8 @@
package com.android.settings.localepicker;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
-import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -27,12 +27,9 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.content.DialogInterface;
import android.os.Bundle;
-import android.os.ResultReceiver;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
@@ -55,6 +52,7 @@ public class LocaleDialogFragmentTest {
public final MockitoRule mockito = MockitoJUnit.rule();
private Context mContext;
+ private LocaleListEditor mLocaleListEditor;
private LocaleDialogFragment mDialogFragment;
private FakeFeatureFactory mFeatureFactory;
@@ -62,30 +60,30 @@ public class LocaleDialogFragmentTest {
public void setUp() throws Exception {
mContext = ApplicationProvider.getApplicationContext();
mDialogFragment = new LocaleDialogFragment();
+ mLocaleListEditor = spy(new LocaleListEditor());
mFeatureFactory = FakeFeatureFactory.setupForTest();
}
- private void setArgument(
- int type, ResultReceiver receiver) {
+ private void setArgument(int type) {
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, type);
args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
- args.putParcelable(ARG_RESULT_RECEIVER, receiver);
mDialogFragment.setArguments(args);
}
@Test
public void getDialogContent_confirmSystemDefault_has2ButtonText() {
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+ setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+ mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+ mLocaleListEditor);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString(
- mContext, "button_label_confirmation_of_system_locale_change"),
+ mContext, "button_label_confirmation_of_system_locale_change"),
dialogContent.mPositiveButton);
assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
dialogContent.mNegativeButton);
@@ -93,9 +91,10 @@ public class LocaleDialogFragmentTest {
@Test
public void getDialogContent_unavailableLocale_has1ButtonText() {
- setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+ mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+ mLocaleListEditor);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
@@ -105,38 +104,9 @@ public class LocaleDialogFragmentTest {
assertTrue(dialogContent.mNegativeButton.isEmpty());
}
- @Test
- public void onClick_clickPositiveButton_sendOK() {
- ResultReceiver resultReceiver = spy(new ResultReceiver(null));
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
- LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
- controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
-
- verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
- verify(mFeatureFactory.metricsFeatureProvider).action(
- mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, true);
- }
-
- @Test
- public void onClick_clickNegativeButton_sendCancel() {
- ResultReceiver resultReceiver = spy(new ResultReceiver(null));
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
- LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
- controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
-
- verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
- verify(mFeatureFactory.metricsFeatureProvider).action(
- mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, false);
- }
-
@Test
public void getMetricsCategory_systemLocaleChange() {
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
-
+ setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
@@ -144,8 +114,7 @@ public class LocaleDialogFragmentTest {
@Test
public void getMetricsCategory_unavailableLocale() {
- setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
-
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);