Snap for 11740859 from 1946b4a669 to 24Q3-release
Change-Id: I4368effe19f203c25fbfeb9f4b3989434e622a07
This commit is contained in:
@@ -112,6 +112,7 @@ android_library {
|
||||
"androidx.test.rules",
|
||||
"telephony_flags_core_java_lib",
|
||||
"setupdesign-lottie-loading-layout",
|
||||
"device_policy_aconfig_flags_lib",
|
||||
],
|
||||
|
||||
plugins: ["androidx.room_room-compiler-plugin"],
|
||||
|
||||
@@ -971,39 +971,6 @@
|
||||
android:value="@string/menu_key_apps"/>
|
||||
</activity>
|
||||
|
||||
<activity-alias
|
||||
android:name="BackupTasksActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:targetActivity=".spa.SpaBridgeActivity"
|
||||
android:label="@string/run_backup_tasks_title">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.REQUEST_RUN_BACKUP_JOBS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.spa.DESTINATION"
|
||||
android:value="TogglePermissionAppList/BackupTasksApps"/>
|
||||
<meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
|
||||
android:value="@string/menu_key_apps"/>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name="AppBackupTasksActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:targetActivity=".spa.SpaAppBridgeActivity"
|
||||
android:label="@string/run_backup_tasks_title">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.REQUEST_RUN_BACKUP_JOBS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.spa.DESTINATION"
|
||||
android:value="TogglePermissionAppInfoPage/BackupTasksApps"/>
|
||||
<meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
|
||||
android:value="@string/menu_key_apps"/>
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
android:name="Settings$DateTimeSettingsActivity"
|
||||
android:label="@string/date_and_time"
|
||||
|
||||
@@ -13,4 +13,14 @@ flag {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -35,3 +35,10 @@ flag {
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -3469,7 +3469,7 @@
|
||||
<!-- Title for the Delete private space settings controller [CHAR LIMIT=40] -->
|
||||
<string name="reset_private_space_delete_title">Delete private space</string>
|
||||
<!-- Delete private space dialog mentioning that private space and the apps in it along with its data will be permanently deleted [CHAR LIMIT=NONE] -->
|
||||
<string name="reset_private_space_delete_dialog">If you have a private space on your device, it will be permanently deleted. All apps in your space and their data will be deleted.</string>
|
||||
<string name="reset_private_space_delete_dialog">If you have a private space on your device, it will be permanently deleted and the Google Account added to your space will be removed.\n\nAll apps in your space and their data will also be permanently deleted.</string>
|
||||
|
||||
<!-- Main Clear -->
|
||||
<!-- Button title to factory data reset the entire device [CHAR LIMIT=NONE] -->
|
||||
@@ -6080,6 +6080,8 @@
|
||||
<string name="battery_usage_chart_label_now">now</string>
|
||||
<!-- [CHAR_LIMIT=NONE] A hyphen for two timestamps. For example, "6 AM - 8 AM", which means "from 6 AM to 8 AM". Please notice the spaces around the hyphen -->
|
||||
<string name="battery_usage_timestamps_hyphen"><xliff:g id="from_timestamp">%1$s</xliff:g> - <xliff:g id="to_timestamp">%2$s</xliff:g></string>
|
||||
<!-- [CHAR_LIMIT=NONE] Accessibility content description for two timestamps. For example, Battery usage for "6 AM to 8 PM" -->
|
||||
<string name="battery_usage_timestamps_content_description"><xliff:g id="from_timestamp">%1$s</xliff:g> to <xliff:g id="to_timestamp">%2$s</xliff:g></string>
|
||||
<!-- [CHAR_LIMIT=NONE] The first slot is a week day (e.g. "Monday"); the second slot is a hourly time span (e.g. "6 AM - 8 AM"). -->
|
||||
<string name="battery_usage_day_and_hour"><xliff:g id="day">%1$s</xliff:g> <xliff:g id="hour">%2$s</xliff:g></string>
|
||||
<!-- [CHAR_LIMIT=NONE] Accessibility content description for each slot in battery chart view. -->
|
||||
@@ -6106,6 +6108,8 @@
|
||||
<string name="battery_usage_spinner_view_by_systems">View by systems</string>
|
||||
<!-- [CHAR_LIMIT=NONE] Less than some percentage, e.g. < 1% -->
|
||||
<string name="battery_usage_less_than_percent">< <xliff:g id="percentage">%1$s</xliff:g></string>
|
||||
<!-- [CHAR_LIMIT=NONE] Accessibility content description for less than some percentage, e.g. less than 1% -->
|
||||
<string name="battery_usage_less_than_percent_content_description">less than <xliff:g id="percentage">%1$s</xliff:g></string>
|
||||
<!-- Process Stats strings -->
|
||||
<skip />
|
||||
<!-- Description of battery information footer text. [CHAR LIMIT=NONE] -->
|
||||
@@ -10426,21 +10430,6 @@
|
||||
<!-- Keywords for settings screen for controlling apps that can run long background tasks [CHAR LIMIT=NONE] -->
|
||||
<string name="keywords_long_background_tasks">long jobs, data transfer, background tasks</string>
|
||||
|
||||
<!-- Title for the settings screen for controlling apps that hold the run backup jobs permission [CHAR LIMIT=60] -->
|
||||
<string name="run_backup_tasks_title">Perform backup tasks in background</string>
|
||||
<!-- Label for the switch to toggle the run backup jobs permission [CHAR LIMIT=100] -->
|
||||
<string name="run_backup_tasks_switch_title">Allow app to run backup-related background tasks</string>
|
||||
<!-- Description that appears below the run_backup_tasks switch [CHAR LIMIT=NONE] -->
|
||||
<string name="run_backup_tasks_footer_title">
|
||||
Indicates that this app has a major use-case where it needs to backup or sync content.
|
||||
Granting this permission allows the app to run in the background for a slightly longer time
|
||||
in order to complete the backup-related work.
|
||||
\n\nIf this permission is denied, the system will not give any special exemption to this
|
||||
app to complete backup-related work in the background.
|
||||
</string>
|
||||
<!-- Keywords for settings screen for controlling apps that hold the run backup tasks permission [CHAR LIMIT=NONE] -->
|
||||
<string name="keywords_run_backup_tasks">backup tasks, backup jobs</string>
|
||||
|
||||
<!-- Reset rate-limiting in the system service ShortcutManager. "ShortcutManager" is the name of a system service and not translatable.
|
||||
If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means
|
||||
the same thing in this context.
|
||||
@@ -13190,4 +13179,7 @@
|
||||
|
||||
<!--Text for acquire msg on UDFPS devices -->
|
||||
<string name="fingerprint_acquired_imager_dirty_udfps">Clean your screen near the sensor and try again</string>
|
||||
|
||||
<!-- Provider Model: summary of converted in SIM category. [CHAR LIMIT=50] -->
|
||||
<string name="sim_category_converted_sim">Converted to eSIM. Remove and discard.</string>
|
||||
</resources>
|
||||
|
||||
@@ -19,16 +19,6 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/special_access">
|
||||
|
||||
<Preference
|
||||
android:key="run_backup_tasks"
|
||||
android:title="@string/run_backup_tasks_title"
|
||||
android:order="-2000"
|
||||
settings:isPreferenceVisible="false"
|
||||
settings:searchable="false"
|
||||
settings:keywords="@string/keywords_run_backup_tasks"
|
||||
settings:controller="com.android.settings.spa.app.specialaccess.BackupTasksAppsPreferenceController">
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:key="manage_external_storage"
|
||||
android:title="@string/manage_external_storage_title"
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
|
||||
import com.android.settings.spa.SpaAppBridgeActivity.Companion.getDestinationForApp
|
||||
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.BackupTasksAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
|
||||
@@ -66,8 +65,6 @@ object SettingsActivityUtil {
|
||||
WifiControlAppListProvider.getAppInfoRoutePrefix(),
|
||||
NfcTagAppsSettingsProvider::class.qualifiedName to
|
||||
NfcTagAppsSettingsProvider.getAppInfoRoutePrefix(),
|
||||
BackupTasksAppsListProvider::class.qualifiedName to
|
||||
BackupTasksAppsListProvider.getAppInfoRoutePrefix(),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -115,6 +115,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
}
|
||||
|
||||
// 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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
}
|
||||
|
||||
@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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
|
||||
@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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
/** 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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
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 class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
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 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
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 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
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 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
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);
|
||||
|
||||
@@ -39,6 +39,9 @@ public interface PowerUsageFeatureProvider {
|
||||
/** 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
|
||||
*/
|
||||
|
||||
@@ -83,6 +83,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAppOptimizationModeLogged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBatteryUsageListScreenOnTimeThresholdInMs() {
|
||||
return 0;
|
||||
|
||||
@@ -404,7 +404,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
}
|
||||
}
|
||||
|
||||
String getSlotInformation() {
|
||||
String getSlotInformation(boolean isAccessibilityText) {
|
||||
if (mDailyViewModel == null || mHourlyViewModels == null) {
|
||||
// No data
|
||||
return null;
|
||||
@@ -413,13 +413,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
return null;
|
||||
}
|
||||
|
||||
final String selectedDayText = mDailyViewModel.getFullText(mDailyChartIndex);
|
||||
final String selectedDayText =
|
||||
isAccessibilityText
|
||||
? mDailyViewModel.getContentDescription(mDailyChartIndex)
|
||||
: mDailyViewModel.getFullText(mDailyChartIndex);
|
||||
if (mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
|
||||
return selectedDayText;
|
||||
}
|
||||
|
||||
final String selectedHourText =
|
||||
mHourlyViewModels.get(mDailyChartIndex).getFullText(mHourlyChartIndex);
|
||||
isAccessibilityText
|
||||
? mHourlyViewModels
|
||||
.get(mDailyChartIndex)
|
||||
.getContentDescription(mHourlyChartIndex)
|
||||
: mHourlyViewModels.get(mDailyChartIndex).getFullText(mHourlyChartIndex);
|
||||
if (isBatteryLevelDataInOneDay()) {
|
||||
return selectedHourText;
|
||||
}
|
||||
@@ -444,7 +451,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
}
|
||||
|
||||
private String getAccessibilityAnnounceMessage() {
|
||||
final String slotInformation = getSlotInformation();
|
||||
final String slotInformation = getSlotInformation(/* isAccessibilityText= */ true);
|
||||
final String slotInformationMessage =
|
||||
slotInformation == null
|
||||
? mPrefContext.getString(
|
||||
@@ -600,6 +607,11 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
|
||||
private abstract class BaseLabelTextGenerator
|
||||
implements BatteryChartViewModel.LabelTextGenerator {
|
||||
@Override
|
||||
public String generateContentDescription(List<Long> timestamps, int index) {
|
||||
return generateFullText(timestamps, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSlotBatteryLevelText(List<Integer> levels, int index) {
|
||||
final int fromBatteryLevelIndex =
|
||||
@@ -673,6 +685,16 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
generateText(timestamps, index + 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateContentDescription(List<Long> timestamps, int index) {
|
||||
return index == timestamps.size() - 1
|
||||
? generateText(timestamps, index)
|
||||
: mContext.getString(
|
||||
R.string.battery_usage_timestamps_content_description,
|
||||
generateText(timestamps, index),
|
||||
generateText(timestamps, index + 1));
|
||||
}
|
||||
|
||||
HourlyChartLabelTextGenerator updateSpecialCaseContext(
|
||||
@NonNull final BatteryLevelData batteryLevelData) {
|
||||
BatteryLevelData.PeriodBatteryLevelData firstDayLevelData =
|
||||
|
||||
@@ -784,7 +784,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
||||
}
|
||||
final AccessibilityNodeInfo childInfo =
|
||||
new AccessibilityNodeInfo(BatteryChartView.this, index);
|
||||
final String slotTimeInfo = mViewModel.getFullText(index);
|
||||
final String slotTimeInfo = mViewModel.getContentDescription(index);
|
||||
final String batteryLevelInfo = mViewModel.getSlotBatteryLevelText(index);
|
||||
onInitializeAccessibilityNodeInfo(childInfo);
|
||||
childInfo.setClickable(isValidToDraw(mViewModel, index));
|
||||
|
||||
@@ -43,9 +43,12 @@ class BatteryChartViewModel {
|
||||
/** Generates the label text. The text may be abbreviated to save space. */
|
||||
String generateText(List<Long> timestamps, int index);
|
||||
|
||||
/** Generates the full text for accessibility. */
|
||||
/** Generates the full text for slot information. */
|
||||
String generateFullText(List<Long> timestamps, int index);
|
||||
|
||||
/** Generates the full text for accessibility. */
|
||||
String generateContentDescription(List<Long> timestamps, int index);
|
||||
|
||||
/** Generates the battery level text of a slot for accessibility.*/
|
||||
String generateSlotBatteryLevelText(List<Integer> levels, int index);
|
||||
}
|
||||
@@ -56,6 +59,7 @@ class BatteryChartViewModel {
|
||||
private final LabelTextGenerator mLabelTextGenerator;
|
||||
private final String[] mTexts;
|
||||
private final String[] mFullTexts;
|
||||
private final String[] mContentDescription;
|
||||
private final String[] mBatteryLevelTexts;
|
||||
|
||||
private int mSelectedIndex = SELECTED_INDEX_ALL;
|
||||
@@ -79,6 +83,7 @@ class BatteryChartViewModel {
|
||||
mLabelTextGenerator = labelTextGenerator;
|
||||
mTexts = new String[size()];
|
||||
mFullTexts = new String[size()];
|
||||
mContentDescription = new String[size()];
|
||||
// Last one for SELECTED_INDEX_ALL
|
||||
mBatteryLevelTexts = new String[size() + 1];
|
||||
}
|
||||
@@ -105,6 +110,14 @@ class BatteryChartViewModel {
|
||||
return mFullTexts[index];
|
||||
}
|
||||
|
||||
public String getContentDescription(int index) {
|
||||
if (mContentDescription[index] == null) {
|
||||
mContentDescription[index] =
|
||||
mLabelTextGenerator.generateContentDescription(mTimestamps, index);
|
||||
}
|
||||
return mContentDescription[index];
|
||||
}
|
||||
|
||||
public String getSlotBatteryLevelText(int index) {
|
||||
final int textIndex = index != SELECTED_INDEX_ALL ? index : size();
|
||||
if (mBatteryLevelTexts[textIndex] == null) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
@VisibleForTesting FooterPreference mFooterPreference;
|
||||
@VisibleForTesting BatteryDiffData mBatteryDiffData;
|
||||
@VisibleForTesting String mPercentLessThanThresholdText;
|
||||
@VisibleForTesting String mPercentLessThanThresholdContentDescription;
|
||||
@VisibleForTesting boolean mIsHighlightSlot;
|
||||
@VisibleForTesting int mAnomalyKeyNumber;
|
||||
@VisibleForTesting String mAnomalyEntryKey;
|
||||
@@ -202,10 +203,14 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY);
|
||||
mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY);
|
||||
mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
|
||||
final String formatPercentage =
|
||||
Utils.formatPercentage(BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD, false);
|
||||
mPercentLessThanThresholdText =
|
||||
mPrefContext.getString(R.string.battery_usage_less_than_percent, formatPercentage);
|
||||
mPercentLessThanThresholdContentDescription =
|
||||
mPrefContext.getString(
|
||||
R.string.battery_usage_less_than_percent,
|
||||
Utils.formatPercentage(BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD, false));
|
||||
R.string.battery_usage_less_than_percent_content_description,
|
||||
formatPercentage);
|
||||
|
||||
mAppListPreferenceGroup.setOrderingAsAdded(false);
|
||||
mSpinnerPreference.initializeSpinner(
|
||||
@@ -394,12 +399,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
|
||||
@VisibleForTesting
|
||||
void setPreferencePercentage(PowerGaugePreference preference, BatteryDiffEntry entry) {
|
||||
preference.setPercentage(
|
||||
entry.getPercentage() < BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD
|
||||
? mPercentLessThanThresholdText
|
||||
: Utils.formatPercentage(
|
||||
entry.getPercentage() + entry.getAdjustPercentageOffset(),
|
||||
/* round= */ true));
|
||||
if (entry.getPercentage() < BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD) {
|
||||
preference.setPercentage(mPercentLessThanThresholdText);
|
||||
preference.setPercentageContentDescription(mPercentLessThanThresholdContentDescription);
|
||||
} else {
|
||||
preference.setPercentage(
|
||||
Utils.formatPercentage(
|
||||
entry.getPercentage() + entry.getAdjustPercentageOffset(),
|
||||
/* round= */ true));
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.util.Log;
|
||||
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 @@ public final class BatteryUsageDataLoader {
|
||||
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 @@ public final class BatteryUsageDataLoader {
|
||||
.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) {
|
||||
|
||||
@@ -345,10 +345,15 @@ public final class ConvertUtils {
|
||||
|
||||
/** 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 @@ public final class ConvertUtils {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@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 @@ public final class ConvertUtils {
|
||||
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 @@ public final class ConvertUtils {
|
||||
.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();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -47,6 +48,7 @@ public class PowerGaugePreference extends AppPreference {
|
||||
private BatteryDiffEntry mBatteryDiffEntry;
|
||||
private CharSequence mContentDescription;
|
||||
private CharSequence mProgress;
|
||||
private CharSequence mProgressContentDescription;
|
||||
private boolean mShowAnomalyIcon;
|
||||
|
||||
public PowerGaugePreference(
|
||||
@@ -87,6 +89,13 @@ public class PowerGaugePreference extends AppPreference {
|
||||
/** Sets the percentage to show. */
|
||||
public void setPercentage(CharSequence percentage) {
|
||||
mProgress = percentage;
|
||||
mProgressContentDescription = percentage;
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
/** Sets the content description of the percentage. */
|
||||
public void setPercentageContentDescription(CharSequence contentDescription) {
|
||||
mProgressContentDescription = contentDescription;
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
@@ -133,6 +142,9 @@ public class PowerGaugePreference extends AppPreference {
|
||||
|
||||
final TextView subtitle = (TextView) view.findViewById(R.id.widget_summary);
|
||||
subtitle.setText(mProgress);
|
||||
if (!TextUtils.isEmpty(mProgressContentDescription)) {
|
||||
subtitle.setContentDescription(mProgressContentDescription);
|
||||
}
|
||||
if (mShowAnomalyIcon) {
|
||||
subtitle.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
R.drawable.ic_warning_24dp, 0, 0, 0);
|
||||
|
||||
@@ -239,7 +239,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
}
|
||||
final int dailyIndex = mBatteryChartPreferenceController.getDailyChartIndex();
|
||||
final int hourlyIndex = mBatteryChartPreferenceController.getHourlyChartIndex();
|
||||
final String slotInformation = mBatteryChartPreferenceController.getSlotInformation();
|
||||
final String slotInformation =
|
||||
mBatteryChartPreferenceController.getSlotInformation(
|
||||
/* isAccessibilityText= */ false);
|
||||
final BatteryDiffData slotUsageData = mBatteryUsageMap.get(dailyIndex).get(hourlyIndex);
|
||||
mScreenOnTimeController.handleSceenOnTimeUpdated(
|
||||
slotUsageData != null ? slotUsageData.getScreenOnTime() : 0L, slotInformation);
|
||||
|
||||
@@ -14,6 +14,13 @@ message BatteryUsageSlot {
|
||||
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 @@ message BatteryUsageDiff {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class NetworkProviderSimListController extends BasePreferenceController i
|
||||
DefaultLifecycleObserver, MobileNetworkRepository.MobileNetworkCallback,
|
||||
DefaultSubscriptionReceiver.DefaultSubscriptionListener {
|
||||
|
||||
private static final String TAG = "NetworkProviderSimListController";
|
||||
private final SubscriptionManager mSubscriptionManager;
|
||||
@Nullable
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
@@ -104,16 +105,21 @@ public class NetworkProviderSimListController extends BasePreferenceController i
|
||||
final Drawable drawable = mContext.getDrawable(
|
||||
info.isEmbedded ? R.drawable.ic_sim_card_download : R.drawable.ic_sim_card);
|
||||
pref.setIcon(drawable);
|
||||
pref.setOnPreferenceClickListener(clickedPref -> {
|
||||
if (!info.isEmbedded && !isActiveSubscriptionId
|
||||
&& !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
|
||||
SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId,
|
||||
true);
|
||||
} else {
|
||||
MobileNetworkUtils.launchMobileNetworkSettings(mContext, info);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (SubscriptionUtil.isConvertedPsimSubscription(mContext, subId)) {
|
||||
// If the subscription has been converted, disable the profile menu.
|
||||
pref.setEnabled(false);
|
||||
} else {
|
||||
pref.setOnPreferenceClickListener(clickedPref -> {
|
||||
if (!info.isEmbedded && !isActiveSubscriptionId
|
||||
&& !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
|
||||
SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId,
|
||||
true);
|
||||
} else {
|
||||
MobileNetworkUtils.launchMobileNetworkSettings(mContext, info);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
mPreferences.put(subId, pref);
|
||||
}
|
||||
for (RestrictedPreference pref : existingPreferences.values()) {
|
||||
@@ -122,6 +128,10 @@ public class NetworkProviderSimListController extends BasePreferenceController i
|
||||
}
|
||||
|
||||
public CharSequence getSummary(SubscriptionInfoEntity subInfo, CharSequence displayName) {
|
||||
if (!subInfo.isEmbedded
|
||||
&& SubscriptionUtil.isConvertedPsimSubscription(mContext, subInfo.getSubId())) {
|
||||
return mContext.getString(R.string.sim_category_converted_sim);
|
||||
}
|
||||
if (subInfo.isActiveSubscriptionId) {
|
||||
CharSequence config = SubscriptionUtil.getDefaultSimConfig(mContext,
|
||||
subInfo.getSubId());
|
||||
|
||||
@@ -549,6 +549,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
|
||||
val intent = Intent(context, SimOnboardingActivity::class.java).apply {
|
||||
putExtra(SUB_ID, subId)
|
||||
}
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.network;
|
||||
|
||||
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
|
||||
import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
|
||||
import static android.telephony.SubscriptionManager.TRANSFER_STATUS_CONVERTED;
|
||||
import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
|
||||
|
||||
import static com.android.internal.util.CollectionUtils.emptyIfNull;
|
||||
@@ -905,4 +906,27 @@ public class SubscriptionUtil {
|
||||
context.getSystemService(ConnectivityManager.class);
|
||||
return connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the subscription with the given subId is converted pSIM.
|
||||
*
|
||||
* @param context {@code Context}
|
||||
* @param subId The subscription ID.
|
||||
*/
|
||||
static boolean isConvertedPsimSubscription(@NonNull Context context, int subId) {
|
||||
SubscriptionManager subscriptionManager = context.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
List<SubscriptionInfo> allSubInofs = subscriptionManager.getAllSubscriptionInfoList();
|
||||
for (SubscriptionInfo subInfo : allSubInofs) {
|
||||
if (subInfo != null) {
|
||||
if (com.android.internal.telephony.flags.Flags.supportPsimToEsimConversion()
|
||||
&& subInfo.getSubscriptionId() == subId
|
||||
&& !subInfo.isEmbedded()
|
||||
&& subInfo.getTransferStatus() == TRANSFER_STATUS_CONVERTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.euicc.EuiccManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
@@ -42,22 +43,20 @@ import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.telephony.flags.Flags;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.network.MobileNetworkRepository;
|
||||
import com.android.settings.network.SubscriptionUtil;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceController implements
|
||||
LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback {
|
||||
|
||||
private static final String TAG = "ConvertToEsimPreference";
|
||||
private Preference mPreference;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private MobileNetworkRepository mMobileNetworkRepository;
|
||||
@@ -113,14 +112,27 @@ public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceCo
|
||||
* To avoid showing users dialogs that can cause confusion,
|
||||
* add conditions to allow conversion in the absence of active eSIM.
|
||||
*/
|
||||
if (!mContext.getResources().getBoolean(R.bool.config_psim_conversion_menu_enabled)
|
||||
|| !isPsimConversionSupport(subId)) {
|
||||
if (!Flags.supportPsimToEsimConversion()) {
|
||||
Log.d(TAG, "supportPsimToEsimConversion flag is not enabled");
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
SubscriptionManager subscriptionManager = mContext.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subId);
|
||||
if (subInfo == null) {
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
EuiccManager euiccManager = (EuiccManager)
|
||||
mContext.getSystemService(Context.EUICC_SERVICE);
|
||||
if (!euiccManager.isPsimConversionSupported(subInfo.getCarrierId())) {
|
||||
Log.i(TAG, "subId is not matched with pSIM conversion"
|
||||
+ " supported carriers:" + subInfo.getCarrierId());
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
if (findConversionSupportComponent()) {
|
||||
return mSubscriptionInfoEntity != null && mSubscriptionInfoEntity.isActiveSubscriptionId
|
||||
&& !mSubscriptionInfoEntity.isEmbedded && isActiveSubscription(subId)
|
||||
&& !hasActiveEsimProfiles()
|
||||
? AVAILABLE
|
||||
: CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
@@ -174,24 +186,6 @@ public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceCo
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasActiveEsimProfiles() {
|
||||
SubscriptionManager subscriptionManager = mContext.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
List<SubscriptionInfo> subscriptionInfoList =
|
||||
SubscriptionUtil.getActiveSubscriptions(subscriptionManager);
|
||||
if (subscriptionInfoList == null || subscriptionInfoList.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
int activatedEsimCount = (int) subscriptionInfoList
|
||||
.stream()
|
||||
.filter(SubscriptionInfo::isEmbedded)
|
||||
.count();
|
||||
if (activatedEsimCount > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean findConversionSupportComponent() {
|
||||
Intent intent = new Intent(EuiccService.ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION);
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
@@ -242,16 +236,4 @@ public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceCo
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isPsimConversionSupport(int subId) {
|
||||
SubscriptionManager subscriptionManager = mContext.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subId);
|
||||
if (subInfo == null) {
|
||||
return false;
|
||||
}
|
||||
final int[] supportedCarriers = mContext.getResources().getIntArray(
|
||||
R.array.config_psim_conversion_menu_enabled_carrier);
|
||||
return Arrays.stream(supportedCarriers).anyMatch(id -> id == subInfo.getCarrierId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
|
||||
@Keep
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
protected SatelliteManager getSatelliteManager(Context context) {
|
||||
return context.getSystemService(SatelliteManager.class);
|
||||
}
|
||||
@@ -359,7 +360,13 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
if (!Flags.carrierEnabledSatelliteFlag()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return mSatelliteManager.getSatellitePlmnsForCarrier(mSubId);
|
||||
|
||||
if (mSatelliteManager != null) {
|
||||
return mSatelliteManager.getSatellitePlmnsForCarrier(mSubId);
|
||||
} else {
|
||||
Log.e(TAG, "mSatelliteManager is null, return empty list");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCarrierConfigChanged(int subId) {
|
||||
|
||||
@@ -76,6 +76,7 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc
|
||||
Intent intent = new Intent(context, ToggleSubscriptionDialogActivity.class);
|
||||
intent.putExtra(ARG_SUB_ID, subId);
|
||||
intent.putExtra(ARG_enable, enable);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
return intent;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ class ZenModesBackend {
|
||||
|
||||
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 {
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationSession;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.ManagedSubscriptionsPolicy;
|
||||
import android.app.admin.flags.Flags;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -374,7 +375,14 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
private int getUserTypeForWipe() {
|
||||
final UserInfo userToBeWiped = mUserManager.getUserInfo(
|
||||
mDevicePolicyManager.getProfileWithMinimumFailedPasswordsForWipe(mEffectiveUserId));
|
||||
if (userToBeWiped == null || userToBeWiped.isPrimary()) {
|
||||
UserHandle primaryUser = UserHandle.SYSTEM;
|
||||
if (Flags.headlessSingleUserFixes()) {
|
||||
UserHandle mainUser = mUserManager.getMainUser();
|
||||
if (mainUser != null ) {
|
||||
primaryUser = mainUser;
|
||||
}
|
||||
}
|
||||
if (userToBeWiped == null || userToBeWiped.getUserHandle().equals(primaryUser)) {
|
||||
return USER_TYPE_PRIMARY;
|
||||
} else if (userToBeWiped.isManagedProfile()) {
|
||||
return USER_TYPE_MANAGED_PROFILE;
|
||||
|
||||
@@ -293,7 +293,6 @@ public class PrivateSpaceMaintainer {
|
||||
*/
|
||||
public synchronized void unlockPrivateSpace(IntentSender intentSender) {
|
||||
if (mUserHandle != null) {
|
||||
Log.d(TAG, "Calling requestQuietModeEnabled to disableQuietMode");
|
||||
mUserManager.requestQuietModeEnabled(false, mUserHandle, intentSender);
|
||||
}
|
||||
}
|
||||
@@ -374,7 +373,6 @@ public class PrivateSpaceMaintainer {
|
||||
*/
|
||||
private final class ProfileAvailabilityBroadcastReceiver extends BroadcastReceiver {
|
||||
void register() {
|
||||
Log.d(TAG, "Registering the receiver");
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
|
||||
mContext.registerReceiver(/* receiver= */ this, filter, Context.RECEIVER_NOT_EXPORTED);
|
||||
|
||||
@@ -125,7 +125,7 @@ public class ResetOptionsDeletePrivateSpaceController extends BasePreferenceCont
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Context context = getContext();
|
||||
return new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.reset_private_space_delete_title)
|
||||
.setTitle(R.string.private_space_delete_header)
|
||||
.setMessage(R.string.reset_private_space_delete_dialog)
|
||||
.setPositiveButton(
|
||||
R.string.private_space_delete_button_label,
|
||||
|
||||
@@ -240,9 +240,9 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment
|
||||
mUseScreenLock.setChecked(isScreenLockUsed());
|
||||
mUseScreenLock.setTitle(getCurrentSecurityTitle(mLockPatternUtils));
|
||||
} else {
|
||||
mFooterPreference.setSummary(getAppPinningContent());
|
||||
mUseScreenLock.setEnabled(false);
|
||||
}
|
||||
mFooterPreference.setSummary(getAppPinningContent());
|
||||
}
|
||||
|
||||
private boolean isGuestModeSupported() {
|
||||
|
||||
@@ -33,7 +33,6 @@ import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID;
|
||||
import static android.telephony.data.ApnSetting.TYPE_MMS;
|
||||
|
||||
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
import static com.android.settings.sim.SimDialogActivity.PICK_DISMISS;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
|
||||
@@ -371,9 +371,7 @@ public class SimSlotChangeHandler {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "Start ToggleSubscriptionDialogActivity with " + subId + " under DSDS+Mep.");
|
||||
Intent intent = ToggleSubscriptionDialogActivity.getIntent(mContext, subId, true);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivityAsUser(intent, UserHandle.SYSTEM);
|
||||
SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId, true);
|
||||
}
|
||||
|
||||
private boolean isMultipleEnabledProfilesSupported() {
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.android.settings.spa.app.backgroundinstall.BackgroundInstalledAppsPag
|
||||
import com.android.settings.spa.app.battery.BatteryOptimizationModeAppListPageProvider
|
||||
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.BackupTasksAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.LongBackgroundTasksAppListProvider
|
||||
@@ -79,7 +78,6 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
|
||||
NfcTagAppsSettingsProvider,
|
||||
LongBackgroundTasksAppListProvider,
|
||||
TurnScreenOnAppsAppListProvider,
|
||||
BackupTasksAppsListProvider,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.android.settings.flags.Flags
|
||||
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
|
||||
import com.android.settings.spa.app.appcompat.UserAspectRatioAppPreference
|
||||
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.BackupTasksAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
|
||||
import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
|
||||
@@ -166,9 +165,6 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
||||
InstallUnknownAppsListProvider.InfoPageEntryItem(app)
|
||||
InteractAcrossProfilesDetailsPreference(app)
|
||||
AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app)
|
||||
if (Flags.enablePerformBackupTasksInSettings()) {
|
||||
BackupTasksAppsListProvider.InfoPageEntryItem(app)
|
||||
}
|
||||
}
|
||||
|
||||
Category(title = stringResource(R.string.app_install_details_group_title)) {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.spa.app.specialaccess
|
||||
|
||||
import android.Manifest
|
||||
import android.app.AppOpsManager
|
||||
import android.app.settings.SettingsEnums
|
||||
import android.content.Context
|
||||
import com.android.settings.R
|
||||
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
|
||||
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
|
||||
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
|
||||
|
||||
object BackupTasksAppsListProvider : TogglePermissionAppListProvider {
|
||||
override val permissionType = "BackupTasksApps"
|
||||
override fun createModel(context: Context) = BackupTasksAppsListModel(context)
|
||||
}
|
||||
|
||||
class BackupTasksAppsListModel(context: Context) : AppOpPermissionListModel(context) {
|
||||
override val pageTitleResId = R.string.run_backup_tasks_title
|
||||
override val switchTitleResId = R.string.run_backup_tasks_switch_title
|
||||
override val footerResId = R.string.run_backup_tasks_footer_title
|
||||
override val appOp = AppOpsManager.OP_RUN_BACKUP_JOBS
|
||||
override val permission = Manifest.permission.RUN_BACKUP_JOBS
|
||||
override val setModeByUid = true
|
||||
|
||||
override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
|
||||
super.setAllowed(record, newAllowed)
|
||||
logPermissionChange(newAllowed)
|
||||
}
|
||||
|
||||
private fun logPermissionChange(newAllowed: Boolean) {
|
||||
featureFactory.metricsFeatureProvider.action(
|
||||
context,
|
||||
SettingsEnums.ACTION_RUN_BACKUP_TASKS_TOGGLE,
|
||||
if (newAllowed) 1 else 0
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.spa.app.specialaccess
|
||||
|
||||
import android.content.Context
|
||||
import androidx.preference.Preference
|
||||
import com.android.settings.core.BasePreferenceController
|
||||
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
|
||||
|
||||
class BackupTasksAppsPreferenceController(context: Context, preferenceKey: String) :
|
||||
BasePreferenceController(context, preferenceKey) {
|
||||
override fun getAvailabilityStatus() = CONDITIONALLY_UNAVAILABLE
|
||||
|
||||
override fun handlePreferenceTreeClick(preference: Preference): Boolean {
|
||||
if (preference.key == mPreferenceKey) {
|
||||
mContext.startSpaActivity(BackupTasksAppsListProvider.getAppListRoute())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,6 @@ object SpecialAppAccessPageProvider : SettingsPageProvider {
|
||||
WifiControlAppListProvider,
|
||||
LongBackgroundTasksAppListProvider,
|
||||
TurnScreenOnAppsAppListProvider,
|
||||
BackupTasksAppsListProvider,
|
||||
)
|
||||
.map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
|
||||
}
|
||||
|
||||
@@ -85,13 +85,16 @@ private fun LabelSimPreference(
|
||||
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 @@ private fun LabelSimPreference(
|
||||
SettingsOutlinedTextField(
|
||||
value = titleSimName,
|
||||
label = stringResource(R.string.sim_onboarding_label_sim_dialog_label),
|
||||
placeholder = {Text(text = originalSimCarrierName)},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
titleSimName = it
|
||||
|
||||
@@ -558,4 +558,49 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,11 @@ public class PowerUsageFeatureProviderImplTest {
|
||||
assertThat(mPowerFeatureProvider.isBatteryTipsEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppOptimizationModeLogged_returnFalse() {
|
||||
assertThat(mPowerFeatureProvider.isAppOptimizationModeLogged()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBatteryUsageListConsumePowerThreshold_return0() {
|
||||
assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0);
|
||||
|
||||
@@ -383,7 +383,7 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = SELECTED_INDEX_ALL;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false)).isEqualTo(null);
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 100% to 66%");
|
||||
}
|
||||
@@ -394,7 +394,7 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false)).isEqualTo(null);
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 100% to 66%");
|
||||
}
|
||||
@@ -405,7 +405,7 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("Sunday");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false)).isEqualTo("Sunday");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 83% to 59%");
|
||||
}
|
||||
@@ -416,8 +416,10 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = 2;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation())
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false))
|
||||
.isEqualTo("10 AM - 12 PM");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(true))
|
||||
.isEqualTo("10 AM to 12 PM");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 97% to 95%");
|
||||
}
|
||||
@@ -428,8 +430,10 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = 8;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation())
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false))
|
||||
.isEqualTo("Sunday 4 PM - 6 PM");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(true))
|
||||
.isEqualTo("Sunday 4 PM to 6 PM");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 67% to 65%");
|
||||
}
|
||||
@@ -440,8 +444,10 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation())
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false))
|
||||
.isEqualTo("7:01 AM - 8 AM");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(true))
|
||||
.isEqualTo("7:01 AM to 8 AM");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 100% to 99%");
|
||||
}
|
||||
@@ -452,7 +458,10 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = 3;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("12 PM - now");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false))
|
||||
.isEqualTo("12 PM - now");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(true))
|
||||
.isEqualTo("12 PM to now");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 95% to 66%");
|
||||
}
|
||||
@@ -463,8 +472,10 @@ public final class BatteryChartPreferenceControllerTest {
|
||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
||||
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation())
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(false))
|
||||
.isEqualTo("7:01 AM - now");
|
||||
assertThat(mBatteryChartPreferenceController.getSlotInformation(true))
|
||||
.isEqualTo("7:01 AM to now");
|
||||
assertThat(mBatteryChartPreferenceController.getBatteryLevelPercentageInfo())
|
||||
.isEqualTo("Battery level percentage from 100% to 66%");
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
|
||||
@Test
|
||||
public void setPreferencePercent_lessThanThreshold_expectedFormat() {
|
||||
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
|
||||
final PowerGaugePreference pref = spy(new PowerGaugePreference(mContext));
|
||||
final BatteryDiffEntry batteryDiffEntry =
|
||||
createBatteryDiffEntry(
|
||||
/* isSystem= */ true,
|
||||
@@ -282,15 +282,18 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
batteryDiffEntry.mConsumePower = 0.8;
|
||||
batteryDiffEntry.setTotalConsumePower(100);
|
||||
mBatteryUsageBreakdownController.mPercentLessThanThresholdText = "< 1%";
|
||||
mBatteryUsageBreakdownController.mPercentLessThanThresholdContentDescription =
|
||||
"test content description";
|
||||
|
||||
mBatteryUsageBreakdownController.setPreferencePercentage(pref, batteryDiffEntry);
|
||||
|
||||
assertThat(pref.getPercentage()).isEqualTo("< 1%");
|
||||
verify(pref).setPercentageContentDescription("test content description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreferencePercent_greaterThanThreshold_expectedFormat() {
|
||||
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
|
||||
final PowerGaugePreference pref = spy(new PowerGaugePreference(mContext));
|
||||
final BatteryDiffEntry batteryDiffEntry =
|
||||
createBatteryDiffEntry(
|
||||
/* isSystem= */ true,
|
||||
@@ -301,10 +304,13 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
batteryDiffEntry.mConsumePower = 16;
|
||||
batteryDiffEntry.setTotalConsumePower(100);
|
||||
mBatteryUsageBreakdownController.mPercentLessThanThresholdText = "< 1%";
|
||||
mBatteryUsageBreakdownController.mPercentLessThanThresholdContentDescription =
|
||||
"test content description";
|
||||
|
||||
mBatteryUsageBreakdownController.setPreferencePercentage(pref, batteryDiffEntry);
|
||||
|
||||
assertThat(pref.getPercentage()).isEqualTo("16%");
|
||||
verify(pref, never()).setPercentageContentDescription(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -382,9 +382,13 @@ public final class ConvertUtilsTest {
|
||||
/* 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 @@ public final class ConvertUtilsTest {
|
||||
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 @@ public final class ConvertUtilsTest {
|
||||
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())
|
||||
|
||||
@@ -101,4 +101,13 @@ public class PowerGaugePreferenceTest {
|
||||
assertThat(mPreferenceViewHolder.findViewById(android.R.id.title).getContentDescription())
|
||||
.isEqualTo(CONTENT_DESCRIPTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnBindViewHolder_bindPercentageContentDescription() {
|
||||
mPowerGaugePreference.setPercentageContentDescription(CONTENT_DESCRIPTION);
|
||||
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
|
||||
|
||||
assertThat(mPreferenceViewHolder.findViewById(R.id.widget_summary).getContentDescription())
|
||||
.isEqualTo(CONTENT_DESCRIPTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public final class ScreenOnTimeControllerTest {
|
||||
@Test
|
||||
public void handleSceenOnTimeUpdated_nullScreenOnTime_hideAllPreference() {
|
||||
mScreenOnTimeController.handleSceenOnTimeUpdated(
|
||||
/* screenOnTime= */ null, "Friday 12:00-now");
|
||||
/* screenOnTime= */ null, "Friday 12:00 to now");
|
||||
|
||||
verify(mRootPreference).setVisible(false);
|
||||
verify(mScreenOnTimeTextPreference).setVisible(false);
|
||||
@@ -84,9 +84,9 @@ public final class ScreenOnTimeControllerTest {
|
||||
|
||||
@Test
|
||||
public void showCategoryTitle_notNull_slotTimestamp() {
|
||||
mScreenOnTimeController.showCategoryTitle("Friday 12:00-now");
|
||||
mScreenOnTimeController.showCategoryTitle("Friday 12:00 to now");
|
||||
|
||||
verify(mRootPreference).setTitle("Screen time for Friday 12:00-now");
|
||||
verify(mRootPreference).setTitle("Screen time for Friday 12:00 to now");
|
||||
verify(mRootPreference).setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,34 +18,48 @@ package com.android.settings.security;
|
||||
|
||||
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 @@ public class ScreenPinningSettingsTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.spa.app.specialaccess
|
||||
|
||||
import android.content.Context
|
||||
import android.platform.test.annotations.RequiresFlagsDisabled
|
||||
import android.platform.test.annotations.RequiresFlagsEnabled
|
||||
import android.platform.test.flag.junit.CheckFlagsRule
|
||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider
|
||||
import androidx.preference.Preference
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import com.android.settings.flags.Flags
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doNothing
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BackupTasksAppsPreferenceControllerTest {
|
||||
|
||||
@get:Rule
|
||||
val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||
doNothing().whenever(mock).startActivity(any())
|
||||
}
|
||||
|
||||
private val matchedPreference = Preference(context).apply { key = preferenceKey }
|
||||
|
||||
private val misMatchedPreference = Preference(context).apply { key = testPreferenceKey }
|
||||
|
||||
private val controller = BackupTasksAppsPreferenceController(context, preferenceKey)
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_PERFORM_BACKUP_TASKS_IN_SETTINGS)
|
||||
fun getAvailabilityStatus_enableBackupTasksApps_returnAvailable() {
|
||||
// Feature is currently disabled so it should return false regardless of flag status.
|
||||
assertThat(controller.isAvailable).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PERFORM_BACKUP_TASKS_IN_SETTINGS)
|
||||
fun getAvailableStatus_disableBackupTasksApps_returnConditionallyUnavailable() {
|
||||
assertThat(controller.isAvailable).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handlePreferenceTreeClick_keyMatched_returnTrue() {
|
||||
assertThat(controller.handlePreferenceTreeClick(matchedPreference)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handlePreferenceTreeClick_keyMisMatched_returnFalse() {
|
||||
assertThat(controller.handlePreferenceTreeClick(misMatchedPreference)).isFalse()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val preferenceKey: String = "backup_tasks_apps"
|
||||
private const val testPreferenceKey: String = "test_key"
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.spa.app.specialaccess
|
||||
|
||||
import android.Manifest
|
||||
import android.app.AppOpsManager
|
||||
import android.content.Context
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.android.settings.R
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BackupTasksAppsTest {
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
private val listModel = BackupTasksAppsListModel(context)
|
||||
|
||||
@Test
|
||||
fun modelResourceIdAndProperties() {
|
||||
assertThat(listModel.pageTitleResId).isEqualTo(R.string.run_backup_tasks_title)
|
||||
assertThat(listModel.switchTitleResId).isEqualTo(R.string.run_backup_tasks_switch_title)
|
||||
assertThat(listModel.footerResId).isEqualTo(R.string.run_backup_tasks_footer_title)
|
||||
assertThat(listModel.appOp).isEqualTo(AppOpsManager.OP_RUN_BACKUP_JOBS)
|
||||
assertThat(listModel.permission).isEqualTo(Manifest.permission.RUN_BACKUP_JOBS)
|
||||
assertThat(listModel.setModeByUid).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -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.graphics.drawable.Drawable;
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
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 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
@Test
|
||||
public void hasNonPrimaryServices_allServicesArePrimary() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(
|
||||
Lists.newArrayList(createCredentialProviderPrimary()));
|
||||
createControllerWithServices(Lists.newArrayList(createCredentialProviderPrimary()));
|
||||
assertThat(controller.hasNonPrimaryServices()).isFalse();
|
||||
}
|
||||
|
||||
@@ -540,8 +567,8 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
public void hasNonPrimaryServices_mixtureOfServices() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(
|
||||
Lists.newArrayList(createCredentialProviderInfo(),
|
||||
createCredentialProviderPrimary()));
|
||||
Lists.newArrayList(
|
||||
createCredentialProviderInfo(), createCredentialProviderPrimary()));
|
||||
assertThat(controller.hasNonPrimaryServices()).isTrue();
|
||||
}
|
||||
|
||||
@@ -599,11 +626,25 @@ public class CredentialManagerPreferenceControllerTest {
|
||||
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user