Merge "Add content description string for '<1%'." into main
diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig
index 3e771cd..3d4f415 100644
--- a/aconfig/settings_bluetooth_declarations.aconfig
+++ b/aconfig/settings_bluetooth_declarations.aconfig
@@ -13,4 +13,14 @@
namespace: "pixel_cross_device_control"
description: "Gates whether to enable checker for bluetooth profile toggle visibility"
bug: "321178209"
+}
+
+flag {
+ name: "hide_le_audio_toggle_for_le_audio_only_device"
+ namespace: "pixel_cross_device_control"
+ description: "Gates whether to hide LeAudio toggle for LeAudio-only device"
+ bug: "333827147"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index ac59f1b..c7a21e9 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -35,3 +35,10 @@
description: "Feature flag to enable injection into PreferenceCategory."
bug: "333547416"
}
+
+flag {
+ name: "slices_retirement"
+ namespace: "android_settings"
+ description: "Feature flag to remove relevant slices dependencies."
+ bug: "297367302"
+}
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index a92b755..ca3786a 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -115,6 +115,7 @@
private @Nullable Delegate mDelegate = null;
private @Nullable String mFlagOverrideForTest = null;
private @Nullable PreferenceScreen mPreferenceScreen = null;
+ private @Nullable PreferenceGroup mPreferenceGroup = null;
private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
private boolean mIsWorkProfile = false;
@@ -161,12 +162,6 @@
return UNSUPPORTED_ON_DEVICE;
}
- // If there is no top provider or any providers in the list then
- // we should hide this pref.
- if (isHiddenDueToNoProviderSet()) {
- return CONDITIONALLY_UNAVAILABLE;
- }
-
if (!hasNonPrimaryServices()) {
return CONDITIONALLY_UNAVAILABLE;
}
@@ -355,24 +350,11 @@
}
// Get the list of new providers and components.
- List<CredentialProviderInfo> newProviders =
+ setAvailableServices(
mCredentialManager.getCredentialProviderServices(
getUser(),
- CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN);
- Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
- Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);
-
- // Get the list of old components
- Set<ComponentName> oldComponents = buildComponentNameSet(mServices, false);
- Set<ComponentName> oldPrimaryComponents = buildComponentNameSet(mServices, true);
-
- // If the sets are equal then don't update the UI.
- if (oldComponents.equals(newComponents)
- && oldPrimaryComponents.equals(newPrimaryComponents)) {
- return;
- }
-
- setAvailableServices(newProviders, null);
+ CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN),
+ null);
if (mPreferenceScreen != null) {
displayPreference(mPreferenceScreen);
@@ -396,11 +378,7 @@
}
@VisibleForTesting
- public boolean isHiddenDueToNoProviderSet() {
- return isHiddenDueToNoProviderSet(getProviders());
- }
-
- private boolean isHiddenDueToNoProviderSet(
+ public boolean isHiddenDueToNoProviderSet(
Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
if (mSimulateHiddenForTests.isPresent()) {
return mSimulateHiddenForTests.get();
@@ -444,17 +422,67 @@
@Override
public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
+ final String prefKey = getPreferenceKey();
+ if (TextUtils.isEmpty(prefKey)) {
+ Log.w(TAG, "Skipping displayPreference because key is empty");
+ return;
+ }
- // Since the UI is being cleared, clear any refs.
+ // Store this reference for later.
+ if (mPreferenceScreen == null) {
+ mPreferenceScreen = screen;
+ mPreferenceGroup = screen.findPreference(prefKey);
+ }
+
+ final Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+
+ maybeUpdateListOfPrefs(providerPair);
+ maybeUpdatePreferenceVisibility(providerPair);
+ }
+
+ private void maybeUpdateListOfPrefs(
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+ if (mPreferenceScreen == null || mPreferenceGroup == null) {
+ return;
+ }
+
+ // Build the new list of prefs.
+ Map<String, CombiPreference> newPrefs =
+ buildPreferenceList(mPreferenceScreen.getContext(), providerPair);
+
+ // Determine if we need to update the prefs.
+ Set<String> existingPrefPackageNames = mPrefs.keySet();
+ if (existingPrefPackageNames.equals(newPrefs.keySet())) {
+ return;
+ }
+
+ // Since the UI is being cleared, clear any refs and prefs.
mPrefs.clear();
+ mPreferenceGroup.removeAll();
- mPreferenceScreen = screen;
- PreferenceGroup group = screen.findPreference(getPreferenceKey());
- group.removeAll();
+ // Populate the preference list with new data.
+ mPrefs.putAll(newPrefs);
+ for (CombiPreference pref : newPrefs.values()) {
+ mPreferenceGroup.addPreference(pref);
+ }
+ }
- Context context = screen.getContext();
- mPrefs.putAll(buildPreferenceList(context, group));
+ private void maybeUpdatePreferenceVisibility(
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+ if (mPreferenceScreen == null || mPreferenceGroup == null) {
+ return;
+ }
+
+ final boolean isAvailable =
+ (getAvailabilityStatus() == AVAILABLE) && !isHiddenDueToNoProviderSet(providerPair);
+
+ if (isAvailable) {
+ mPreferenceScreen.addPreference(mPreferenceGroup);
+ mPreferenceGroup.setVisible(true);
+ } else {
+ mPreferenceScreen.removePreference(mPreferenceGroup);
+ mPreferenceGroup.setVisible(false);
+ }
}
/**
@@ -511,9 +539,9 @@
/** Aggregates the list of services and builds a list of UI prefs to show. */
@VisibleForTesting
public @NonNull Map<String, CombiPreference> buildPreferenceList(
- @NonNull Context context, @NonNull PreferenceGroup group) {
- // Get the providers and extract the values.
- Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+ @NonNull Context context,
+ @NonNull Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+ // Extract the values.
CombinedProviderInfo topProvider = providerPair.second;
List<CombinedProviderInfo> providers = providerPair.first;
@@ -554,7 +582,6 @@
combinedInfo.getSettingsActivity(),
combinedInfo.getDeviceAdminRestrictions(context, getUser()));
output.put(packageName, pref);
- group.addPreference(pref);
}
// Set the visibility if we have services.
@@ -1023,11 +1050,12 @@
public void onClick(View buttonView) {
// Forward the event.
if (mSwitch != null && mOnClickListener != null) {
- if (!mOnClickListener.onCheckChanged(CombiPreference.this, mSwitch.isChecked())) {
- // The update was not successful since there were too
- // many enabled providers to manually reset any state.
- mChecked = false;
- mSwitch.setChecked(false);
+ if (!mOnClickListener.onCheckChanged(
+ CombiPreference.this, mSwitch.isChecked())) {
+ // The update was not successful since there were too
+ // many enabled providers to manually reset any state.
+ mChecked = false;
+ mSwitch.setChecked(false);
}
}
}
@@ -1083,8 +1111,10 @@
if (mSwitch != null && !TextUtils.isEmpty(appName)) {
mSwitch.setContentDescription(
- getContext().getString(
- R.string.credman_on_off_switch_content_description, appName));
+ getContext()
+ .getString(
+ R.string.credman_on_off_switch_content_description,
+ appName));
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 943d99b..3fa811a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -43,6 +43,7 @@
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HeadsetProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -512,6 +513,19 @@
refresh();
}
+ private boolean isLeAudioOnlyDevice() {
+ if (mCachedDevice.getProfiles().stream()
+ .noneMatch(profile -> profile instanceof LeAudioProfile)) {
+ return false;
+ }
+ return mCachedDevice.getProfiles().stream()
+ .noneMatch(
+ profile ->
+ profile instanceof HearingAidProfile
+ || profile instanceof A2dpProfile
+ || profile instanceof HeadsetProfile);
+ }
+
private void updateLeAudioConfig() {
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
@@ -520,6 +534,13 @@
boolean isLeEnabledByDefault =
SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true);
mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
+ if (Flags.hideLeAudioToggleForLeAudioOnlyDevice() && isLeAudioOnlyDevice()) {
+ mIsLeAudioToggleEnabled = false;
+ Log.d(
+ TAG,
+ "Hide LeAudio toggle for LeAudio-only Device: "
+ + mCachedDevice.getDevice().getAnonymizedAddress());
+ }
Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
+ ", LE_AUDIO_TOGGLE_VISIBLE_PROPERTY:" + isLeAudioToggleVisible
+ ", LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY:" + isLeEnabledByDefault);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 35a173b..dd30e69 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -39,6 +39,9 @@
/** Check whether the battery tips card is enabled in the battery usage page */
boolean isBatteryTipsEnabled();
+ /** Check whether to log the optimization mode of app entry in period job */
+ boolean isAppOptimizationModeLogged();
+
/**
* Returns a threshold (in milliseconds) for the minimal screen on time in battery usage list
*/
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index f0616ed..5c66dbc 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -84,6 +84,11 @@
}
@Override
+ public boolean isAppOptimizationModeLogged() {
+ return false;
+ }
+
+ @Override
public double getBatteryUsageListScreenOnTimeThresholdInMs() {
return 0;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java
new file mode 100644
index 0000000..6b35fb9
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 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.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.util.ArrayMap;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.fuelgauge.BatteryOptimizeUtils;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import java.util.Map;
+
+/** A cache to log battery optimization mode of an app */
+final class BatteryOptimizationModeCache {
+ private static final String TAG = "BatteryOptimizationModeCache";
+
+ @VisibleForTesting final Map<Integer, BatteryOptimizationMode> mBatteryOptimizeModeCacheMap;
+
+ private final Context mContext;
+
+ BatteryOptimizationModeCache(final Context context) {
+ mContext = context;
+ mBatteryOptimizeModeCacheMap = new ArrayMap<>();
+ PowerAllowlistBackend.getInstance(mContext).refreshList();
+ }
+
+ BatteryOptimizationMode getBatteryOptimizeMode(final int uid, final String packageName) {
+ if (!mBatteryOptimizeModeCacheMap.containsKey(uid)) {
+ final BatteryOptimizeUtils batteryOptimizeUtils =
+ new BatteryOptimizeUtils(mContext, uid, packageName);
+ mBatteryOptimizeModeCacheMap.put(
+ uid,
+ BatteryOptimizationMode.forNumber(
+ batteryOptimizeUtils.getAppOptimizationMode(/* refreshList= */ false)));
+ }
+ return mBatteryOptimizeModeCacheMap.get(uid);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index 870faec..26bb6dd 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -27,6 +27,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
import com.android.settings.overlay.FeatureFactory;
@@ -124,9 +125,15 @@
userIdsSeries,
/* isFromPeriodJob= */ true,
batteryDiffDataMap -> {
+ final PowerUsageFeatureProvider featureProvider =
+ FeatureFactory.getFeatureFactory()
+ .getPowerUsageFeatureProvider();
DatabaseUtils.sendBatteryUsageSlotData(
context,
- ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap));
+ ConvertUtils.convertToBatteryUsageSlotList(
+ context,
+ batteryDiffDataMap,
+ featureProvider.isAppOptimizationModeLogged()));
if (batteryDiffDataMap.values().stream()
.anyMatch(
data ->
@@ -135,12 +142,10 @@
.isEmpty()
|| !data.getAppDiffEntryList()
.isEmpty()))) {
- FeatureFactory.getFeatureFactory()
- .getPowerUsageFeatureProvider()
- .detectPowerAnomaly(
- context,
- /* displayDrain= */ 0,
- DetectRequestSourceType.TYPE_DATA_LOADER);
+ featureProvider.detectPowerAnomaly(
+ context,
+ /* displayDrain= */ 0,
+ DetectRequestSourceType.TYPE_DATA_LOADER);
}
});
if (batteryLevelData == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index df9f063..1cbe6da 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -345,10 +345,15 @@
/** Converts from {@link Map<Long, BatteryDiffData>} to {@link List<BatteryUsageSlot>} */
public static List<BatteryUsageSlot> convertToBatteryUsageSlotList(
- final Map<Long, BatteryDiffData> batteryDiffDataMap) {
+ final Context context,
+ final Map<Long, BatteryDiffData> batteryDiffDataMap,
+ final boolean isAppOptimizationModeLogged) {
List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
+ final BatteryOptimizationModeCache optimizationModeCache =
+ isAppOptimizationModeLogged ? new BatteryOptimizationModeCache(context) : null;
for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) {
- batteryUsageSlotList.add(convertToBatteryUsageSlot(batteryDiffData));
+ batteryUsageSlotList.add(
+ convertToBatteryUsageSlot(batteryDiffData, optimizationModeCache));
}
return batteryUsageSlotList;
}
@@ -479,9 +484,10 @@
}
}
-
@VisibleForTesting
- static BatteryUsageDiff convertToBatteryUsageDiff(BatteryDiffEntry batteryDiffEntry) {
+ static BatteryUsageDiff convertToBatteryUsageDiff(
+ final BatteryDiffEntry batteryDiffEntry,
+ final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
BatteryUsageDiff.Builder builder =
BatteryUsageDiff.newBuilder()
.setUid(batteryDiffEntry.mUid)
@@ -511,11 +517,18 @@
if (batteryDiffEntry.mLegacyLabel != null) {
builder.setLabel(batteryDiffEntry.mLegacyLabel);
}
+ // Log the battery optimization mode of AppEntry while converting to batteryUsageSlot.
+ if (optimizationModeCache != null && !batteryDiffEntry.isSystemEntry()) {
+ builder.setAppOptimizationMode(
+ optimizationModeCache.getBatteryOptimizeMode(
+ (int) batteryDiffEntry.mUid, batteryDiffEntry.getPackageName()));
+ }
return builder.build();
}
private static BatteryUsageSlot convertToBatteryUsageSlot(
- final BatteryDiffData batteryDiffData) {
+ final BatteryDiffData batteryDiffData,
+ final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
if (batteryDiffData == null) {
return BatteryUsageSlot.getDefaultInstance();
}
@@ -527,10 +540,11 @@
.setEndBatteryLevel(batteryDiffData.getEndBatteryLevel())
.setScreenOnTime(batteryDiffData.getScreenOnTime());
for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getAppDiffEntryList()) {
- builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+ builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache));
}
for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) {
- builder.addSystemUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+ builder.addSystemUsage(
+ convertToBatteryUsageDiff(batteryDiffEntry, /* optimizationModeCache= */ null));
}
return builder.build();
}
diff --git a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
index 7f67770..4e3e3c4 100644
--- a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
+++ b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
@@ -14,6 +14,13 @@
repeated BatteryUsageDiff system_usage = 7;
}
+enum BatteryOptimizationMode {
+ MODE_UNKNOWN = 0;
+ MODE_RESTRICTED = 1;
+ MODE_UNRESTRICTED = 2;
+ MODE_OPTIMIZED = 3;
+}
+
message BatteryUsageDiff {
optional int64 uid = 1;
optional int64 user_id = 2;
@@ -32,4 +39,5 @@
optional int64 background_usage_time = 15;
optional int64 screen_on_time = 16;
optional int64 foreground_service_usage_time = 17;
+ optional BatteryOptimizationMode app_optimization_mode = 18;
}
diff --git a/src/com/android/settings/notification/modes/ZenModesBackend.java b/src/com/android/settings/notification/modes/ZenModesBackend.java
index 388f13b..d6a2ef5 100644
--- a/src/com/android/settings/notification/modes/ZenModesBackend.java
+++ b/src/com/android/settings/notification/modes/ZenModesBackend.java
@@ -141,7 +141,7 @@
void deactivateMode(ZenMode mode) {
if (mode.isManualDnd()) {
- // TODO: b/326061620 - This shouldn't snooze any rules that are active.
+ // When calling with fromUser=true this will not snooze other modes.
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG,
/* fromUser= */ true);
} else {
diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java
index 4d3743c..45c3d84 100644
--- a/src/com/android/settings/security/ScreenPinningSettings.java
+++ b/src/com/android/settings/security/ScreenPinningSettings.java
@@ -240,9 +240,9 @@
mUseScreenLock.setChecked(isScreenLockUsed());
mUseScreenLock.setTitle(getCurrentSecurityTitle(mLockPatternUtils));
} else {
- mFooterPreference.setSummary(getAppPinningContent());
mUseScreenLock.setEnabled(false);
}
+ mFooterPreference.setSummary(getAppPinningContent());
}
private boolean isGuestModeSupported() {
diff --git a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
index 66b7d4b..2b40a91 100644
--- a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
@@ -85,13 +85,16 @@
onboardingService: SimOnboardingService,
subInfo: SubscriptionInfo,
) {
+ val originalSimCarrierName = subInfo.displayName.toString()
var titleSimName by remember {
mutableStateOf(onboardingService.getSubscriptionInfoDisplayName(subInfo))
}
val phoneNumber = phoneNumber(subInfo)
val alertDialogPresenter = rememberAlertDialogPresenter(
confirmButton = AlertDialogButton(stringResource(R.string.mobile_network_sim_name_rename)) {
- onboardingService.addItemForRenaming(subInfo, titleSimName)
+ onboardingService.addItemForRenaming(
+ subInfo, if (titleSimName.isEmpty()) originalSimCarrierName else titleSimName
+ )
},
dismissButton = AlertDialogButton(stringResource(R.string.cancel)) {
titleSimName = onboardingService.getSubscriptionInfoDisplayName(subInfo)
@@ -105,6 +108,7 @@
SettingsOutlinedTextField(
value = titleSimName,
label = stringResource(R.string.sim_onboarding_label_sim_dialog_label),
+ placeholder = {Text(text = originalSimCarrierName)},
modifier = Modifier.fillMaxWidth()
) {
titleSimName = it
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
index 9b1466b..9b92234 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
@@ -558,4 +558,49 @@
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.get(0).isVisible()).isTrue();
}
+
+ @Test
+ public void classicAudioDeviceWithLeAudio_showLeAudioToggle() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
+ setupDevice(makeDefaultDeviceConfig());
+
+ LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
+ when(leAudioProfile.getNameResource(mDevice))
+ .thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
+ when(leAudioProfile.isProfileReady()).thenReturn(true);
+ when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
+ when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
+ mConnectableProfiles.add(leAudioProfile);
+ when(mCachedDevice.getProfiles())
+ .thenAnswer(
+ invocation ->
+ ImmutableList.of(
+ leAudioProfile, addMockA2dpProfile(false, false, false)));
+
+ showScreen(mController);
+
+ List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
+ assertThat(switches.get(0).isVisible()).isTrue();
+ }
+
+ @Test
+ public void leAudioOnlyDevice_hideLeAudioToggle() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
+ setupDevice(makeDefaultDeviceConfig());
+
+ LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
+ when(leAudioProfile.getNameResource(mDevice))
+ .thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
+ when(leAudioProfile.isProfileReady()).thenReturn(true);
+ when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
+ when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
+ mConnectableProfiles.add(leAudioProfile);
+ when(mCachedDevice.getProfiles())
+ .thenAnswer(invocation -> ImmutableList.of(leAudioProfile));
+
+ showScreen(mController);
+
+ List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
+ assertThat(switches.get(0).isVisible()).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index db4c359..3158688 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -73,6 +73,11 @@
}
@Test
+ public void testIsAppOptimizationModeLogged_returnFalse() {
+ assertThat(mPowerFeatureProvider.isAppOptimizationModeLogged()).isFalse();
+ }
+
+ @Test
public void testGetBatteryUsageListConsumePowerThreshold_return0() {
assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0);
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index 5ce449b..3ed2dd1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -382,9 +382,13 @@
/* foregroundServiceUsageConsumePower= */ 1.3,
/* backgroundUsageConsumePower= */ 1.4,
/* cachedUsageConsumePower= */ 1.5);
+ BatteryOptimizationModeCache optimizationModeCache =
+ new BatteryOptimizationModeCache(mContext);
+ optimizationModeCache.mBatteryOptimizeModeCacheMap.put(
+ (int) batteryDiffEntry.mUid, BatteryOptimizationMode.MODE_OPTIMIZED);
final BatteryUsageDiff batteryUsageDiff =
- ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry);
+ ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache);
assertThat(batteryUsageDiff.getUid()).isEqualTo(101L);
assertThat(batteryUsageDiff.getUserId()).isEqualTo(1001L);
@@ -402,6 +406,8 @@
assertThat(batteryUsageDiff.getBackgroundUsageTime()).isEqualTo(5678L);
assertThat(batteryUsageDiff.getScreenOnTime()).isEqualTo(123L);
assertThat(batteryUsageDiff.getKey()).isEqualTo("key");
+ assertThat(batteryUsageDiff.getAppOptimizationMode())
+ .isEqualTo(BatteryOptimizationMode.MODE_OPTIMIZED);
assertThat(batteryUsageDiff.hasPackageName()).isFalse();
assertThat(batteryUsageDiff.hasLabel()).isFalse();
}
@@ -591,7 +597,7 @@
Map.of(11L, batteryDiffData1, 21L, batteryDiffData2, 31L, batteryDiffData3);
final List<BatteryUsageSlot> batteryUsageSlotList =
- ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap);
+ ConvertUtils.convertToBatteryUsageSlotList(mContext, batteryDiffDataMap, false);
assertThat(batteryUsageSlotList).hasSize(3);
assertThat(batteryUsageSlotList.stream().map((s) -> s.getScreenOnTime()).sorted().toList())
diff --git a/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java b/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
index 045ef65..99b41f4 100644
--- a/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
@@ -18,34 +18,48 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.robolectric.Shadows.shadowOf;
+
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
+import android.icu.text.MessageFormat;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import androidx.fragment.app.Fragment;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.widget.FooterPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowUserManager;
import java.util.List;
+import java.util.function.Consumer;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowLockPatternUtils.class)
public class ScreenPinningSettingsTest {
-
+ private static final String KEY_FOOTER = "screen_pinning_settings_screen_footer";
private Context mContext;
+ private UserManager mUserManager;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
+ mUserManager = mContext.getSystemService(UserManager.class);
}
@After
@@ -110,4 +124,97 @@
assertThat(indexRaws.get(0).title).isEqualTo(
mContext.getString(R.string.screen_pinning_unlock_none));
}
+
+ @Test
+ public void onCreate_lockToAppEnabled_guestModeSupported_verifyFooterText() {
+ setupLockToAppState(/* enabled= */ true);
+ setupGuestModeState(/* supported= */ true);
+
+ launchFragmentAndRunTest(fragment -> {
+ FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+ assertThat(footer.getSummary())
+ .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true));
+ });
+ }
+
+ @Test
+ public void onCreate_lockToAppEnabled_guestModeNotSupported_verifyFooterText() {
+ setupLockToAppState(/* enabled= */ true);
+ setupGuestModeState(/* supported= */ false);
+
+ launchFragmentAndRunTest(fragment -> {
+ FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+ assertThat(footer.getSummary())
+ .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false));
+ });
+ }
+
+ @Test
+ public void onCreate_lockToAppDisabled_guestModeSupported_verifyFooterText() {
+ setupLockToAppState(/* enabled= */ false);
+ setupGuestModeState(/* supported= */ true);
+
+ launchFragmentAndRunTest(fragment -> {
+ FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+ assertThat(footer.getSummary())
+ .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true));
+ });
+ }
+
+ @Test
+ public void onCreate_lockToAppDisabled_guestModeNotSupported_verifyFooterText() {
+ setupLockToAppState(/* enabled= */ false);
+ setupGuestModeState(/* supported= */ false);
+
+ launchFragmentAndRunTest(fragment -> {
+ FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+ assertThat(footer.getSummary())
+ .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false));
+ });
+ }
+
+ private CharSequence getExpectedFooterText(boolean guestModeSupported) {
+ final int stringResource = guestModeSupported
+ ? R.string.screen_pinning_guest_user_description
+ : R.string.screen_pinning_description;
+ return MessageFormat.format(mContext.getString(stringResource), 1, 2, 3);
+ }
+
+ private void setupLockToAppState(boolean enabled) {
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED,
+ enabled ? 1 : 0);
+ }
+
+ private void setupGuestModeState(boolean supported) {
+ ShadowUserManager shadowUserManager = shadowOf(mUserManager);
+ shadowUserManager.setSupportsMultipleUsers(supported);
+ shadowUserManager.setUserRestriction(
+ UserHandle.of(UserHandle.myUserId()), UserManager.DISALLOW_USER_SWITCH, !supported);
+ }
+
+ private void launchFragmentAndRunTest(Consumer<ScreenPinningSettings> test) {
+ Intent intent = new Intent();
+ intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
+ SecurityAdvancedSettings.class.getName());
+ // ScreenPinningSettings is tightly coupled with the SettingsActivity
+ // In order to successfully launch the ScreenPinningSettings, have to use an indirect route
+ // to launch the SecurityAdvancedSetting first, then replace it with ScreenPinningSettings.
+ try (ActivityController<SettingsActivity> controller =
+ ActivityController.of(new SettingsActivity(), intent)) {
+ controller.create().start().resume();
+
+ controller.get().getSupportFragmentManager().beginTransaction().replace(
+ R.id.main_content, ScreenPinningSettings.class, null).commitNow();
+ Fragment fragment = controller.get().getSupportFragmentManager()
+ .findFragmentById(R.id.main_content);
+ assertThat(fragment).isNotNull();
+ assertThat(fragment).isInstanceOf(ScreenPinningSettings.class);
+
+ test.accept((ScreenPinningSettings) fragment);
+ }
+ }
}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index c0023ee..3cd1533 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -17,7 +17,6 @@
package com.android.settings.applications.credentials;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -36,7 +35,9 @@
import android.net.Uri;
import android.os.Looper;
import android.provider.Settings;
+import android.util.Pair;
+import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
@@ -124,19 +125,37 @@
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
- public void getAvailabilityStatus_isHidden_returnsConditionallyUnavailable() {
+ public void isHiddenDueToNoProviderSet_hiddenDueToEmptyPair() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
- controller.setSimulateConnectedForTests(true);
- assertThat(controller.isConnected()).isTrue();
- controller.setSimulateHiddenForTests(Optional.of(true));
- assertThat(controller.isHiddenDueToNoProviderSet()).isTrue();
- assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isTrue();
+ }
+
+ @Test
+ public void isHiddenDueToNoProviderSet_hiddenDueToNoPrimaryProvider() {
+ CredentialManagerPreferenceController controller =
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> testPair =
+ new Pair<>(Lists.newArrayList(createCombinedProviderInfo()), null);
+ assertThat(controller.isHiddenDueToNoProviderSet(testPair)).isTrue();
+ }
+
+ @Test
+ public void isHiddenDueToNoProviderSet_validDataSoNotHidden() {
+ CredentialManagerPreferenceController controller =
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> testPair =
+ new Pair<>(
+ Lists.newArrayList(createCombinedProviderInfo()),
+ createCombinedProviderInfo());
+ assertThat(controller.isHiddenDueToNoProviderSet(testPair)).isFalse();
}
@Test
@@ -146,7 +165,7 @@
controller.setSimulateConnectedForTests(true);
controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
assertThat(controller.isConnected()).isTrue();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
@@ -170,7 +189,7 @@
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -214,7 +233,7 @@
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Ensure that we stay under 5 providers (one is reserved for primary).
@@ -283,7 +302,7 @@
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -336,17 +355,26 @@
createControllerWithServices(
Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
controller.setSimulateConnectedForTests(true);
- controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.isConnected()).isTrue();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- controller.displayPreference(mScreen);
- assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
+ CombinedProviderInfo combinedProviderA =
+ new CombinedProviderInfo(Lists.newArrayList(serviceA1), null, false, false);
+ CombinedProviderInfo combinedProviderB =
+ new CombinedProviderInfo(Lists.newArrayList(serviceB1), null, false, false);
+ CombinedProviderInfo combinedProviderC =
+ new CombinedProviderInfo(
+ Lists.newArrayList(serviceC1, serviceC2, serviceC3), null, false, false);
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair =
+ createPair(
+ Lists.newArrayList(combinedProviderA, combinedProviderB, combinedProviderC),
+ createCombinedProviderInfo());
+
+ assertThat(controller.isHiddenDueToNoProviderSet(providerPair)).isFalse();
Map<String, CredentialManagerPreferenceController.CombiPreference> prefs =
- controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory);
+ controller.buildPreferenceList(mContext, providerPair);
assertThat(prefs.keySet())
.containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C);
assertThat(prefs.size()).isEqualTo(3);
@@ -531,8 +559,7 @@
@Test
public void hasNonPrimaryServices_allServicesArePrimary() {
CredentialManagerPreferenceController controller =
- createControllerWithServices(
- Lists.newArrayList(createCredentialProviderPrimary()));
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderPrimary()));
assertThat(controller.hasNonPrimaryServices()).isFalse();
}
@@ -540,8 +567,8 @@
public void hasNonPrimaryServices_mixtureOfServices() {
CredentialManagerPreferenceController controller =
createControllerWithServices(
- Lists.newArrayList(createCredentialProviderInfo(),
- createCredentialProviderPrimary()));
+ Lists.newArrayList(
+ createCredentialProviderInfo(), createCredentialProviderPrimary()));
assertThat(controller.hasNonPrimaryServices()).isTrue();
}
@@ -599,11 +626,25 @@
private CredentialProviderInfo createCredentialProviderPrimary() {
return createCredentialProviderInfoBuilder(
- "com.android.primary", "CredManProvider", "Service Label", "App Name")
+ "com.android.primary", "CredManProvider", "Service Label", "App Name")
.setPrimary(true)
.build();
}
+ private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> createPair() {
+ return createPair(Lists.newArrayList(), null);
+ }
+
+ private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> createPair(
+ List<CombinedProviderInfo> providers, @Nullable CombinedProviderInfo primaryProvider) {
+ return new Pair<>(providers, primaryProvider);
+ }
+
+ private CombinedProviderInfo createCombinedProviderInfo() {
+ return new CombinedProviderInfo(
+ Lists.newArrayList(createCredentialProviderInfo()), null, false, false);
+ }
+
private CredentialProviderInfo createCredentialProviderInfoWithSubtitle(
String packageName, String className, CharSequence label, CharSequence subtitle) {
ServiceInfo si = new ServiceInfo();