Snap for 10147226 from 174bd2ab74 to udc-release

Change-Id: Idb0a9f28c69f39df0600fb58d5f2b144e791f149
This commit is contained in:
Android Build Coastguard Worker
2023-05-16 23:33:26 +00:00
28 changed files with 594 additions and 845 deletions

View File

@@ -3717,7 +3717,7 @@
<!-- Show channel-level notification settings (channel passed in as extras) -->
<activity android:name=".notification.app.ChannelPanelActivity"
android:label="@string/notification_channel_title"
android:theme="@style/Theme.Panel"
android:theme="@style/Theme.Panel.Material"
android:excludeFromRecents="true"
android:configChanges="keyboardHidden|screenSize"
android:exported="true">

View File

@@ -2,6 +2,20 @@
"presubmit": [
{
"name": "SettingsSpaUnitTests"
},
{
"name": "SettingsUnitTests",
"options": [
{
"include-filter": "com.android.settings.password"
},
{
"include-filter": "com.android.settings.biometrics"
},
{
"include-filter": "com.android.settings.biometrics2"
}
]
}
],
"postsubmit": [

View File

@@ -15,10 +15,7 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid
android:color="?androidprv:attr/materialColorSurfaceContainer" />
<stroke
android:width="2dp"
android:color="?android:attr/colorAccent"/>

View File

@@ -18,7 +18,7 @@
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/notification_importance_button_unselected"/>
android:color="?android:attr/colorAccent"/>
<corners android:radius="@dimen/rect_button_radius" />
</shape>

View File

@@ -1,24 +1,31 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
Copyright (C) 2023 The Android Open Source Project
<selector xmlns:android="http://schemas.android.com/apk/res/android">
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:drawable="@drawable/ic_check_circle_filled_24dp" />
<item
android:state_checked="false"
android:drawable="@drawable/ic_circle_outline_24dp" />
</selector>
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp">
<selector>
<item
android:state_checked="true"
android:drawable="@drawable/ic_check_circle_filled_24dp" />
<item
android:state_checked="false"
android:drawable="@drawable/ic_circle_outline_24dp" />
</selector>
</item>
</layer-list>

View File

@@ -74,7 +74,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:paddingLeft="14dp"
android:text="@string/auto_pin_confirm_user_message"
android:textSize="16sp"
android:button="@drawable/checkbox_circle_shape"

View File

@@ -4243,7 +4243,7 @@
<string name="accessibility_screen_magnification_follow_typing_title">Magnify typing</string>
<!-- Summary for accessibility follow typing preference for magnification. [CHAR LIMIT=none] -->
<string name="accessibility_screen_magnification_follow_typing_summary">Magnifier follows text as you type</string>
<!-- Title for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=35] -->
<!-- Title for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=60] -->
<string name="accessibility_screen_magnification_always_on_title">Keep on while switching apps</string>
<!-- Summary for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=none] -->
<string name="accessibility_screen_magnification_always_on_summary">Magnifier stays on and zooms out when you switch apps</string>

View File

@@ -227,6 +227,9 @@
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
</style>
<style name="Theme.Panel.Material" parent="Theme.Panel" >
<item name="android:switchStyle">@style/Switch.SettingsLib</item>
</style>
<!-- Material theme for the pages containing TabLayout and ViewPager -->
<style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@*android:color/edge_effect_device_default_light</item>

View File

@@ -193,6 +193,8 @@
android:key="long_background_tasks"
android:title="@string/long_background_tasks_title"
android:summary="@string/summary_placeholder"
settings:isPreferenceVisible="false"
settings:searchable="false"
settings:controller="com.android.settings.applications.appinfo.LongBackgroundTasksDetailsPreferenceController" />
</PreferenceCategory>

View File

@@ -128,6 +128,8 @@
android:title="@string/long_background_tasks_title"
android:order="-800"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
settings:isPreferenceVisible="false"
settings:searchable="false"
settings:keywords="@string/keywords_long_background_tasks"
settings:controller="com.android.settings.applications.specialaccess.applications.LongBackgroundTaskController">
<extra

View File

@@ -16,10 +16,6 @@
package com.android.settings.applications;
import static android.Manifest.permission.RUN_USER_INITIATED_JOBS;
import static android.app.AppOpsManager.OP_RUN_USER_INITIATED_JOBS;
import static android.app.AppOpsManager.opToPermission;
import android.Manifest;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -345,7 +341,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
@Override
public boolean isLongBackgroundTaskPermissionToggleSupported() {
return TextUtils.equals(RUN_USER_INITIATED_JOBS,
opToPermission(OP_RUN_USER_INITIATED_JOBS));
// Since the RUN_USER_INITIATED_JOBS permission related to this controller is a normal
// app-op permission allowed by default, this should always return false - if it is ever
// converted to a special app-op permission, this should be updated.
return false;
}
}

View File

@@ -75,6 +75,9 @@ public class ClonedAppsPreferenceController extends BasePreferenceController
}
private void updatePreferenceSummary() {
if (!isAvailable()) {
return;
}
new AsyncTask<Void, Void, Integer[]>() {
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,6 +37,6 @@ public class LongBackgroundTaskController extends BasePreferenceController {
@Override
public int getAvailabilityStatus() {
return mAppFeatureProvider.isLongBackgroundTaskPermissionToggleSupported()
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
}

View File

@@ -28,11 +28,9 @@ import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/**
* Dialog fragment for reboot confirmation when enabling certain features.
*/
/** Dialog fragment for reboot confirmation when enabling certain features. */
public class RebootConfirmationDialogFragment extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
private static final String TAG = "FreeformPrefRebootDlg";
@@ -40,18 +38,17 @@ public class RebootConfirmationDialogFragment extends InstrumentedDialogFragment
private final int mCancelButtonId;
private final RebootConfirmationDialogHost mHost;
/**
* Show an instance of this dialog.
*/
/** Show an instance of this dialog. */
public static void show(Fragment fragment, int messageId, RebootConfirmationDialogHost host) {
show(fragment, messageId, R.string.reboot_dialog_reboot_later, host);
}
/**
* Show an instance of this dialog with cancel button string set as cancelButtonId
*/
public static void show(Fragment fragment, int messageId,
int cancelButtonId, RebootConfirmationDialogHost host) {
/** Show an instance of this dialog with cancel button string set as cancelButtonId */
public static void show(
Fragment fragment,
int messageId,
int cancelButtonId,
RebootConfirmationDialogHost host) {
final FragmentManager manager = fragment.getActivity().getSupportFragmentManager();
if (manager.findFragmentByTag(TAG) == null) {
final RebootConfirmationDialogFragment dialog =
@@ -60,8 +57,8 @@ public class RebootConfirmationDialogFragment extends InstrumentedDialogFragment
}
}
private RebootConfirmationDialogFragment(int messageId,
int cancelButtonId, RebootConfirmationDialogHost host) {
private RebootConfirmationDialogFragment(
int messageId, int cancelButtonId, RebootConfirmationDialogHost host) {
mMessageId = messageId;
mCancelButtonId = cancelButtonId;
mHost = host;
@@ -89,4 +86,10 @@ public class RebootConfirmationDialogFragment extends InstrumentedDialogFragment
mHost.onRebootCancelled();
}
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
mHost.onRebootDialogDismissed();
}
}

View File

@@ -20,22 +20,20 @@ import android.content.Context;
import android.content.Intent;
/**
* Host of {@link RebootConfirmationDialogFragment} that provides callback when user
* interacts with the UI.
* Host of {@link RebootConfirmationDialogFragment} that provides callback when user interacts with
* the UI.
*/
public interface RebootConfirmationDialogHost {
/**
* Called when user made a decision to reboot the device.
*/
/** Called when user made a decision to reboot the device. */
default void onRebootConfirmed(Context context) {
// user presses button "Reboot now", reboot the device
final Intent intent = new Intent(Intent.ACTION_REBOOT);
context.startActivity(intent);
}
/**
* Called when user made a decision to cancel the reboot
* Default to do nothing
*/
/** Called when user made a decision to cancel the reboot Default to do nothing */
default void onRebootCancelled() {}
/** Called when reboot dialog is dismissed Default to do nothing */
default void onRebootDialogDismissed() {}
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.development.graphicsdriver;
import android.content.Context;
import android.content.Intent;
import android.os.GraphicsEnvironment;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -33,9 +34,7 @@ import com.android.settings.development.RebootConfirmationDialogFragment;
import com.android.settings.development.RebootConfirmationDialogHost;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
/**
* Controller to handle the events when user toggles this developer option switch: Enable ANGLE
*/
/** Controller to handle the events when user toggles this developer option switch: Enable ANGLE */
public class GraphicsDriverEnableAngleAsSystemDriverController
extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener,
@@ -50,14 +49,15 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
private final GraphicsDriverSystemPropertiesWrapper mSystemProperties;
private boolean mShouldToggleSwitchBackOnRebootDialogDismiss;
@VisibleForTesting
static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@VisibleForTesting
static final String PROPERTY_PERSISTENT_GRAPHICS_EGL = "persist.graphics.egl";
@VisibleForTesting
static final String ANGLE_DRIVER_SUFFIX = "angle";
@VisibleForTesting static final String ANGLE_DRIVER_SUFFIX = "angle";
@VisibleForTesting
static class Injector {
@@ -87,6 +87,10 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
super(context);
mFragment = fragment;
mSystemProperties = injector.createSystemPropertiesWrapper();
// By default, when the reboot dialog is dismissed we want to toggle the switch back.
// Exception is when user chooses to reboot now, the switch should keep its current value
// and persist its' state over reboot.
mShouldToggleSwitchBackOnRebootDialogDismiss = true;
}
@Override
@@ -108,11 +112,12 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@VisibleForTesting
void showRebootDialog() {
RebootConfirmationDialogFragment.show(
mFragment, R.string.reboot_dialog_enable_angle_as_system_driver,
R.string.cancel, this);
mFragment,
R.string.reboot_dialog_enable_angle_as_system_driver,
R.string.cancel,
this);
}
@Override
public void updateState(Preference preference) {
// set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
@@ -120,8 +125,9 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
final String currentGlesDriver =
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
final boolean isAngleSupported = TextUtils
.equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
final boolean isAngleSupported =
TextUtils.equals(
mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported);
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -130,8 +136,9 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
protected void onDeveloperOptionsSwitchEnabled() {
// only enable the switch if ro.gfx.angle.supported is true
// we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor
final boolean isAngleSupported = TextUtils
.equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
final boolean isAngleSupported =
TextUtils.equals(
mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -145,9 +152,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
((SwitchPreference) mPreference).setEnabled(false);
}
@Override
public void onRebootCancelled() {
// if user presses button "Cancel", do not reboot the device, and toggles switch back
void toggleSwitchBack() {
final String currentGlesDriver =
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
if (TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver)) {
@@ -169,4 +174,40 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
// if persist.graphics.egl holds values other than the above two, log error message
Log.e(TAG, "Invalid persist.graphics.egl property value");
}
@VisibleForTesting
void rebootDevice(Context context) {
final Intent intent = new Intent(Intent.ACTION_REBOOT);
context.startActivity(intent);
}
@Override
public void onRebootConfirmed(Context context) {
// User chooses to reboot now, do not toggle switch back
mShouldToggleSwitchBackOnRebootDialogDismiss = false;
// Reboot the device
rebootDevice(context);
}
@Override
public void onRebootCancelled() {
// User chooses to cancel reboot, toggle switch back
mShouldToggleSwitchBackOnRebootDialogDismiss = true;
}
@Override
public void onRebootDialogDismissed() {
// If reboot dialog is dismissed either from
// 1) User clicks cancel
// 2) User taps phone screen area outside of reboot dialog
// do not reboot the device, and toggles switch back.
if (mShouldToggleSwitchBackOnRebootDialogDismiss) {
toggleSwitchBack();
}
// Reset the flag so that the default option is to toggle switch back
// on reboot dialog dismissed.
mShouldToggleSwitchBackOnRebootDialogDismiss = true;
}
}

View File

@@ -25,17 +25,20 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.IDeviceIdleController;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import java.io.IOException;
@@ -49,13 +52,22 @@ import java.util.List;
public final class BatteryBackupHelper implements BackupHelper {
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
// Definition for the device build information.
public static final String KEY_BUILD_BRAND = "device_build_brand";
public static final String KEY_BUILD_PRODUCT = "device_build_product";
public static final String KEY_BUILD_MANUFACTURER = "device_build_manufacture";
public static final String KEY_BUILD_FINGERPRINT = "device_build_fingerprint";
// Customized fields for device extra information.
public static final String KEY_BUILD_METADATA_1 = "device_build_metadata_1";
public static final String KEY_BUILD_METADATA_2 = "device_build_metadata_2";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
private static final String BATTERY_OPTIMIZE_BACKUP_FILE_NAME =
"battery_optimize_backup_historical_logs";
private static final int DEVICE_BUILD_INFO_SIZE = 6;
static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":";
static final String KEY_FULL_POWER_LIST = "full_power_list";
static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
@VisibleForTesting
@@ -70,7 +82,13 @@ public final class BatteryBackupHelper implements BackupHelper {
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
private byte[] mOptimizationModeBytes;
private boolean mVerifyMigrateConfiguration = false;
private final Context mContext;
// Device information map from the restoreEntity() method.
private final ArrayMap<String, String> mDeviceBuildInfoMap =
new ArrayMap<>(DEVICE_BUILD_INFO_SIZE);
public BatteryBackupHelper(Context context) {
mContext = context.getApplicationContext();
@@ -83,41 +101,58 @@ public final class BatteryBackupHelper implements BackupHelper {
Log.w(TAG, "ignore performBackup() for non-owner or empty data");
return;
}
final List<String> allowlistedApps = backupFullPowerList(data);
if (allowlistedApps != null) {
backupOptimizationMode(data, allowlistedApps);
final List<String> allowlistedApps = getFullPowerList();
if (allowlistedApps == null) {
return;
}
writeBackupData(data, KEY_BUILD_BRAND, Build.BRAND);
writeBackupData(data, KEY_BUILD_PRODUCT, Build.PRODUCT);
writeBackupData(data, KEY_BUILD_MANUFACTURER, Build.MANUFACTURER);
writeBackupData(data, KEY_BUILD_FINGERPRINT, Build.FINGERPRINT);
// Add customized device build metadata fields.
final PowerUsageFeatureProvider provider = FeatureFactory.getFactory(mContext)
.getPowerUsageFeatureProvider(mContext);
writeBackupData(data, KEY_BUILD_METADATA_1, provider.getBuildMetadata1(mContext));
writeBackupData(data, KEY_BUILD_METADATA_2, provider.getBuildMetadata2(mContext));
backupOptimizationMode(data, allowlistedApps);
}
@Override
public void restoreEntity(BackupDataInputStream data) {
BatterySettingsMigrateChecker.verifySaverConfiguration(mContext);
// Ensure we only verify the migrate configuration one time.
if (!mVerifyMigrateConfiguration) {
mVerifyMigrateConfiguration = true;
BatterySettingsMigrateChecker.verifySaverConfiguration(mContext);
}
if (!isOwner() || data == null || data.size() == 0) {
Log.w(TAG, "ignore restoreEntity() for non-owner or empty data");
return;
}
if (KEY_OPTIMIZATION_LIST.equals(data.getKey())) {
final int dataSize = data.size();
final byte[] dataBytes = new byte[dataSize];
try {
data.read(dataBytes, 0 /*offset*/, dataSize);
} catch (IOException e) {
Log.e(TAG, "failed to load BackupDataInputStream", e);
return;
}
final int restoreCount = restoreOptimizationMode(dataBytes);
if (restoreCount > 0) {
BatterySettingsMigrateChecker.verifyOptimizationModes(mContext);
}
final String dataKey = data.getKey();
switch (dataKey) {
case KEY_BUILD_BRAND:
case KEY_BUILD_PRODUCT:
case KEY_BUILD_MANUFACTURER:
case KEY_BUILD_FINGERPRINT:
case KEY_BUILD_METADATA_1:
case KEY_BUILD_METADATA_2:
restoreBackupData(dataKey, data);
break;
case KEY_OPTIMIZATION_LIST:
// Hold the optimization mode data until all conditions are matched.
mOptimizationModeBytes = getBackupData(dataKey, data);
break;
}
performRestoreIfNeeded();
}
@Override
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
private List<String> backupFullPowerList(BackupDataOutput data) {
private List<String> getFullPowerList() {
final long timestamp = System.currentTimeMillis();
String[] allowlistedApps;
try {
@@ -131,10 +166,7 @@ public final class BatteryBackupHelper implements BackupHelper {
Log.w(TAG, "no data found in the getFullPowerList()");
return new ArrayList<>();
}
final String allowedApps = String.join(DELIMITER, allowlistedApps);
writeBackupData(data, KEY_FULL_POWER_LIST, allowedApps);
Log.d(TAG, String.format("backup getFullPowerList() size=%d in %d/ms",
Log.d(TAG, String.format("getFullPowerList() size=%d in %d/ms",
allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
return Arrays.asList(allowlistedApps);
}
@@ -224,6 +256,23 @@ public final class BatteryBackupHelper implements BackupHelper {
return restoreCount;
}
private void performRestoreIfNeeded() {
if (mOptimizationModeBytes == null || mOptimizationModeBytes.length == 0) {
return;
}
final PowerUsageFeatureProvider provider = FeatureFactory.getFactory(mContext)
.getPowerUsageFeatureProvider(mContext);
if (!provider.isValidToRestoreOptimizationMode(mDeviceBuildInfoMap)) {
return;
}
// Start to restore the app optimization mode data.
final int restoreCount = restoreOptimizationMode(mOptimizationModeBytes);
if (restoreCount > 0) {
BatterySettingsMigrateChecker.verifyOptimizationModes(mContext);
}
mOptimizationModeBytes = null; // clear data
}
/** Dump the app optimization mode backup history data. */
public static void dumpHistoricalData(Context context, PrintWriter writer) {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(
@@ -303,8 +352,33 @@ public final class BatteryBackupHelper implements BackupHelper {
return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager());
}
private void restoreBackupData(String dataKey, BackupDataInputStream data) {
final byte[] dataBytes = getBackupData(dataKey, data);
if (dataBytes == null || dataBytes.length == 0) {
return;
}
final String dataContent = new String(dataBytes, StandardCharsets.UTF_8);
mDeviceBuildInfoMap.put(dataKey, dataContent);
Log.d(TAG, String.format("restore:%s:%s", dataKey, dataContent));
}
private static byte[] getBackupData(String dataKey, BackupDataInputStream data) {
final int dataSize = data.size();
final byte[] dataBytes = new byte[dataSize];
try {
data.read(dataBytes, 0 /*offset*/, dataSize);
} catch (IOException e) {
Log.e(TAG, "failed to getBackupData() " + dataKey, e);
return null;
}
return dataBytes;
}
private static void writeBackupData(
BackupDataOutput data, String dataKey, String dataContent) {
if (dataContent == null || dataContent.isEmpty()) {
return;
}
final byte[] dataContentBytes = dataContent.getBytes();
try {
data.writeEntityHeader(dataKey, dataContentBytes.length);
@@ -312,5 +386,6 @@ public final class BatteryBackupHelper implements BackupHelper {
} catch (IOException e) {
Log.e(TAG, "writeBackupData() is failed for " + dataKey, e);
}
Log.d(TAG, String.format("backup:%s:%s", dataKey, dataContent));
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
import android.util.ArrayMap;
import android.util.SparseIntArray;
import com.android.settingslib.fuelgauge.Estimate;
@@ -166,4 +167,19 @@ public interface PowerUsageFeatureProvider {
* Returns {@link Set} for ignoring task root class names for screen on time
*/
Set<String> getIgnoreScreenOnTimeTaskRootSet();
/**
* Returns the customized device build information for data backup
*/
String getBuildMetadata1(Context context);
/**
* Returns the customized device build information for data backup
*/
String getBuildMetadata2(Context context);
/**
* Whether the app optimization mode is valid to restore
*/
boolean isValidToRestoreOptimizationMode(ArrayMap<String, String> deviceInfoMap);
}

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseIntArray;
@@ -188,4 +189,19 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
public Set<String> getIgnoreScreenOnTimeTaskRootSet() {
return new ArraySet<>();
}
@Override
public String getBuildMetadata1(Context context) {
return null;
}
@Override
public String getBuildMetadata2(Context context) {
return null;
}
@Override
public boolean isValidToRestoreOptimizationMode(ArrayMap<String, String> deviceInfoMap) {
return false;
}
}

View File

@@ -19,6 +19,8 @@ package com.android.settings.regionalpreferences;
import android.content.Context;
import android.provider.Settings;
import androidx.core.text.util.LocalePreferences;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;

View File

@@ -1,605 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.regionalpreferences;
import android.icu.number.LocalizedNumberFormatter;
import android.icu.number.NumberFormatter;
import android.icu.text.DateFormat;
import android.icu.text.DateTimePatternGenerator;
import android.icu.util.MeasureUnit;
import android.os.Build.VERSION;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringDef;
import androidx.core.os.BuildCompat;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
import java.util.Locale.Category;
/**
* TODO(b/263861083) This is a temp file and will replace it to Androidx version.
* Provides friendly APIs to get the user's locale preferences. The data can refer to
* external/cldr/common/main/en.xml.
*/
public final class LocalePreferences {
private static final String TAG = LocalePreferences.class.getSimpleName();
/** APIs to get the user's preference of the hour cycle. */
public static class HourCycle {
private static final String U_EXTENSION_OF_HOUR_CYCLE = "hc";
/** 12 Hour System (0-11) */
public static final String H11 = "h11";
/** 12 Hour System (1-12) */
public static final String H12 = "h12";
/** 24 Hour System (0-23) */
public static final String H23 = "h23";
/** 24 Hour System (1-24) */
public static final String H24 = "h24";
/** Default hour cycle for the locale */
public static final String DEFAULT = "";
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@StringDef({
H11,
H12,
H23,
H24,
DEFAULT
})
@Retention(RetentionPolicy.SOURCE)
public @interface HourCycleTypes {
}
private HourCycle() {
}
}
/**
* Return the user's preference of the hour cycle which is from
* {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and
* bases on the {@code Locale#getDefault(Locale.Category)}. E.g. "h23"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@HourCycle.HourCycleTypes
public static String getHourCycle() {
return getHourCycle(true);
}
/**
* Return the hour cycle setting of the inputted {@link Locale}. The returned result is resolved
* and bases on the inputted {@code Locale}.
* E.g. "h23"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@HourCycle.HourCycleTypes
public static String getHourCycle(@NonNull Locale locale) {
return getHourCycle(locale, true);
}
/**
* Return the user's preference of the hour cycle which is from
* {@link Locale#getDefault(Locale.Category)}. E.g. "h23"
*
* @param resolved If the {@code Locale#getDefault(Locale.Category)} contains hour cycle subtag,
* this argument is ignored. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
* and the resolved argument is true, this function tries to find the default
* hour cycle for the {@code Locale#getDefault(Locale.Category)}. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
* and the resolved argument is false, this function returns empty string
* i.e. HourCycle.Default.
* @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
* in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
* i.e. HourCycle.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@HourCycle.HourCycleTypes
public static String getHourCycle(
boolean resolved) {
return getHourCycle(Api33Impl.getDefaultLocale(), resolved);
}
/**
* Return the hour cycle setting of the inputted {@link Locale}. E.g. "en-US-u-hc-h23".
*
* @param locale The {@code Locale} to get the hour cycle.
* @param resolved If the given {@code Locale} contains hour cycle subtag, this argument is
* ignored. If the given {@code Locale} doesn't contain hour cycle subtag and
* the resolved argument is true, this function tries to find the default
* hour cycle for the given {@code Locale}. If the given {@code Locale} doesn't
* contain hour cycle subtag and the resolved argument is false, this function
* return empty string i.e. HourCycle.Default.
* @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
* in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
* i.e. HourCycle.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@HourCycle.HourCycleTypes
public static String getHourCycle(@NonNull Locale locale, boolean resolved) {
if (!BuildCompat.isAtLeastT()) {
throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
}
return Api33Impl.getHourCycle(locale, resolved);
}
/** APIs to get the user's preference of Calendar. */
public static class CalendarType {
private static final String U_EXTENSION_OF_CALENDAR = "ca";
/** Chinese Calendar */
public static final String CHINESE = "chinese";
/** Dangi Calendar (Korea Calendar) */
public static final String DANGI = "dangi";
/** Gregorian Calendar */
public static final String GREGORIAN = "gregorian";
/** Hebrew Calendar */
public static final String HEBREW = "hebrew";
/** Indian National Calendar */
public static final String INDIAN = "indian";
/** Islamic Calendar */
public static final String ISLAMIC = "islamic";
/** Islamic Calendar (tabular, civil epoch) */
public static final String ISLAMIC_CIVIL = "islamic-civil";
/** Islamic Calendar (Saudi Arabia, sighting) */
public static final String ISLAMIC_RGSA = "islamic-rgsa";
/** Islamic Calendar (tabular, astronomical epoch) */
public static final String ISLAMIC_TBLA = "islamic-tbla";
/** Islamic Calendar (Umm al-Qura) */
public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
/** Persian Calendar */
public static final String PERSIAN = "persian";
/** Default calendar for the locale */
public static final String DEFAULT = "";
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@StringDef({
CHINESE,
DANGI,
GREGORIAN,
HEBREW,
INDIAN,
ISLAMIC,
ISLAMIC_CIVIL,
ISLAMIC_RGSA,
ISLAMIC_TBLA,
ISLAMIC_UMALQURA,
PERSIAN,
DEFAULT
})
@Retention(RetentionPolicy.SOURCE)
public @interface CalendarTypes {
}
private CalendarType() {
}
}
/**
* Return the user's preference of the calendar type which is from {@link
* Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on
* the {@code Locale#getDefault(Locale.Category)} settings. E.g. "chinese"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@CalendarType.CalendarTypes
public static String getCalendarType() {
return getCalendarType(true);
}
/**
* Return the calendar type of the inputted {@link Locale}. The returned result is resolved and
* bases on the inputted {@link Locale} settings.
* E.g. "chinese"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@CalendarType.CalendarTypes
public static String getCalendarType(@NonNull Locale locale) {
return getCalendarType(locale, true);
}
/**
* Return the user's preference of the calendar type which is from {@link
* Locale#getDefault(Locale.Category)}. E.g. "chinese"
*
* @param resolved If the {@code Locale#getDefault(Locale.Category)} contains calendar type
* subtag, this argument is ignored. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
* subtag and the resolved argument is true, this function tries to find
* the default calendar type for the
* {@code Locale#getDefault(Locale.Category)}. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
* subtag and the resolved argument is false, this function returns empty string
* i.e. CalendarTypes.Default.
* @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
* specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
* empty string i.e. CalendarTypes.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@CalendarType.CalendarTypes
public static String getCalendarType(boolean resolved) {
return getCalendarType(Api33Impl.getDefaultLocale(), resolved);
}
/**
* Return the calendar type of the inputted {@link Locale}. E.g. "chinese"
*
* @param locale The {@link Locale} to get the calendar type.
* @param resolved If the given {@code Locale} contains calendar type subtag, this argument is
* ignored. If the given {@code Locale} doesn't contain calendar type subtag and
* the resolved argument is true, this function tries to find the default
* calendar type for the given {@code Locale}. If the given {@code Locale}
* doesn't contain calendar type subtag and the resolved argument is false, this
* function return empty string i.e. CalendarTypes.Default.
* @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
* specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
* empty string i.e. CalendarTypes.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@CalendarType.CalendarTypes
public static String getCalendarType(@NonNull Locale locale, boolean resolved) {
if (!BuildCompat.isAtLeastT()) {
throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
}
return Api33Impl.getCalendarType(locale, resolved);
}
/** APIs to get the user's preference of temperature unit. */
public static class TemperatureUnit {
private static final String U_EXTENSION_OF_TEMPERATURE_UNIT = "mu";
/** Celsius */
public static final String CELSIUS = "celsius";
/** Fahrenheit */
public static final String FAHRENHEIT = "fahrenhe";
/** Kelvin */
public static final String KELVIN = "kelvin";
/** Default Temperature for the locale */
public static final String DEFAULT = "";
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@StringDef({
CELSIUS,
FAHRENHEIT,
KELVIN,
DEFAULT
})
@Retention(RetentionPolicy.SOURCE)
public @interface TemperatureUnits {
}
private TemperatureUnit() {
}
}
/**
* Return the user's preference of the temperature unit which is from {@link
* Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
* {@code Locale#getDefault(Locale.Category)} settings. E.g. "fahrenhe"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@TemperatureUnit.TemperatureUnits
public static String getTemperatureUnit() {
return getTemperatureUnit(true);
}
/**
* Return the temperature unit of the inputted {@link Locale}. The returned result is resolved
* and bases on the inputted {@code Locale} settings. E.g. "fahrenhe"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@TemperatureUnit.TemperatureUnits
public static String getTemperatureUnit(
@NonNull Locale locale) {
return getTemperatureUnit(locale, true);
}
/**
* Return the user's preference of the temperature unit which is from {@link
* Locale#getDefault(Locale.Category)}. E.g. "fahrenhe"
*
* @param resolved If the {@code Locale#getDefault(Locale.Category)} contains temperature unit
* subtag, this argument is ignored. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
* subtag and the resolved argument is true, this function tries to find
* the default temperature unit for the
* {@code Locale#getDefault(Locale.Category)}. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
* subtag and the resolved argument is false, this function returns empty string
* i.e. TemperatureUnits.Default.
* @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
* specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
* empty string i.e. TemperatureUnits.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@TemperatureUnit.TemperatureUnits
public static String getTemperatureUnit(boolean resolved) {
return getTemperatureUnit(Api33Impl.getDefaultLocale(), resolved);
}
/**
* Return the temperature unit of the inputted {@link Locale}. E.g. "fahrenheit"
*
* @param locale The {@link Locale} to get the temperature unit.
* @param resolved If the given {@code Locale} contains temperature unit subtag, this argument
* is ignored. If the given {@code Locale} doesn't contain temperature unit
* subtag and the resolved argument is true, this function tries to find
* the default temperature unit for the given {@code Locale}. If the given
* {@code Locale} doesn't contain temperature unit subtag and the resolved
* argument is false, this function return empty string
* i.e. TemperatureUnits.Default.
* @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
* specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
* empty string i.e. TemperatureUnits.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@TemperatureUnit.TemperatureUnits
public static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
if (!BuildCompat.isAtLeastT()) {
throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
}
return Api33Impl.getTemperatureUnit(locale, resolved);
}
/** APIs to get the user's preference of the first day of week. */
public static class FirstDayOfWeek {
private static final String U_EXTENSION_OF_FIRST_DAY_OF_WEEK = "fw";
/** Sunday */
public static final String SUNDAY = "sun";
/** Monday */
public static final String MONDAY = "mon";
/** Tuesday */
public static final String TUESDAY = "tue";
/** Wednesday */
public static final String WEDNESDAY = "wed";
/** Thursday */
public static final String THURSDAY = "thu";
/** Friday */
public static final String FRIDAY = "fri";
/** Saturday */
public static final String SATURDAY = "sat";
/** Default first day of week for the locale */
public static final String DEFAULT = "";
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@StringDef({
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
DEFAULT
})
@Retention(RetentionPolicy.SOURCE)
public @interface Days {
}
private FirstDayOfWeek() {
}
}
/**
* Return the user's preference of the first day of week which is from
* {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
* {@code Locale#getDefault(Locale.Category)} settings. E.g. "sun"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@FirstDayOfWeek.Days
public static String getFirstDayOfWeek() {
return getFirstDayOfWeek(true);
}
/**
* Return the first day of week of the inputted {@link Locale}. The returned result is resolved
* and bases on the inputted {@code Locale} settings.
* E.g. "sun"
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
public static @FirstDayOfWeek.Days String getFirstDayOfWeek(@NonNull Locale locale) {
return getFirstDayOfWeek(locale, true);
}
/**
* Return the user's preference of the first day of week which is from {@link
* Locale#getDefault(Locale.Category)}. E.g. "sun"
*
* @param resolved If the {@code Locale#getDefault(Locale.Category)} contains first day of week
* subtag, this argument is ignored. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
* subtag and the resolved argument is true, this function tries to find
* the default first day of week for the
* {@code Locale#getDefault(Locale.Category)}. If the
* {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
* subtag and the resolved argument is false, this function returns empty string
* i.e. Days.Default.
* @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was specified
* in the first day of week subtag, e.g. en-US-u-fw-days, this function returns empty string
* i.e. Days.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@FirstDayOfWeek.Days
public static String getFirstDayOfWeek(boolean resolved) {
return getFirstDayOfWeek(Api33Impl.getDefaultLocale(), resolved);
}
/**
* Return the first day of week of the inputted {@link Locale}. E.g. "sun"
*
* @param locale The {@link Locale} to get the first day of week.
* @param resolved If the given {@code Locale} contains first day of week subtag, this argument
* is ignored. If the given {@code Locale} doesn't contain first day of week
* subtag and the resolved argument is true, this function tries to find
* the default first day of week for the given {@code Locale}. If the given
* {@code Locale} doesn't contain first day of week subtag and the resolved
* argument is false, this function return empty string i.e. Days.Default.
* @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was
* specified in the first day of week subtag, e.g. en-US-u-fw-days, this function returns
* empty string i.e. Days.Default.
*/
@NonNull
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
@FirstDayOfWeek.Days
public static String getFirstDayOfWeek(
@NonNull Locale locale, boolean resolved) {
if (!BuildCompat.isAtLeastT()) {
throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
}
return Api33Impl.getFirstDayOfWeek(locale, resolved);
}
private static class Api33Impl {
@DoNotInline
@HourCycle.HourCycleTypes
static String getHourCycle(@NonNull Locale locale,
boolean resolved) {
String hc = locale.getUnicodeLocaleType(HourCycle.U_EXTENSION_OF_HOUR_CYCLE);
if (hc != null) {
return hc;
}
if (!resolved) {
return HourCycle.DEFAULT;
}
return getHourCycleType(
DateTimePatternGenerator.getInstance(locale).getDefaultHourCycle());
}
@DoNotInline
@CalendarType.CalendarTypes
static String getCalendarType(@NonNull Locale locale, boolean resolved) {
String ca = locale.getUnicodeLocaleType(CalendarType.U_EXTENSION_OF_CALENDAR);
if (ca != null) {
return ca;
}
if (!resolved) {
return CalendarType.DEFAULT;
}
return android.icu.util.Calendar.getInstance(locale).getType();
}
@DoNotInline
@TemperatureUnit.TemperatureUnits
static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
String mu =
locale.getUnicodeLocaleType(TemperatureUnit.U_EXTENSION_OF_TEMPERATURE_UNIT);
if (mu != null) {
return mu;
}
if (!resolved) {
return TemperatureUnit.DEFAULT;
}
return getResolvedTemperatureUnit(locale);
}
@DoNotInline
@FirstDayOfWeek.Days
static String getFirstDayOfWeek(@NonNull Locale locale, boolean resolved) {
String mu =
locale.getUnicodeLocaleType(FirstDayOfWeek.U_EXTENSION_OF_FIRST_DAY_OF_WEEK);
if (mu != null) {
return mu;
}
if (!resolved) {
return FirstDayOfWeek.DEFAULT;
}
// TODO(b/262294472) Use {@code android.icu.util.Calendar} instead of
// {@code java.util.Calendar}.
return getStringOfFirstDayOfWeek(
java.util.Calendar.getInstance(locale).getFirstDayOfWeek());
}
@DoNotInline
static Locale getDefaultLocale() {
return Locale.getDefault(Category.FORMAT);
}
private static String getStringOfFirstDayOfWeek(int fw) {
String[] arrDays = {
FirstDayOfWeek.SUNDAY,
FirstDayOfWeek.MONDAY,
FirstDayOfWeek.TUESDAY,
FirstDayOfWeek.WEDNESDAY,
FirstDayOfWeek.THURSDAY,
FirstDayOfWeek.FRIDAY,
FirstDayOfWeek.SATURDAY};
return fw >= 1 && fw <= 7 ? arrDays[fw - 1] : FirstDayOfWeek.DEFAULT;
}
@HourCycle.HourCycleTypes
private static String getHourCycleType(
DateFormat.HourCycle hourCycle) {
switch (hourCycle) {
case HOUR_CYCLE_11:
return HourCycle.H11;
case HOUR_CYCLE_12:
return HourCycle.H12;
case HOUR_CYCLE_23:
return HourCycle.H23;
case HOUR_CYCLE_24:
return HourCycle.H24;
default:
return HourCycle.DEFAULT;
}
}
@TemperatureUnit.TemperatureUnits
private static String getResolvedTemperatureUnit(@NonNull Locale locale) {
LocalizedNumberFormatter nf = NumberFormatter.with()
.usage("temperature")
.unit(MeasureUnit.CELSIUS)
.locale(locale);
String unit = nf.format(1).getOutputUnit().getIdentifier();
if (unit.contains(TemperatureUnit.FAHRENHEIT)) {
return TemperatureUnit.FAHRENHEIT;
}
return unit;
}
private Api33Impl() {
}
}
private LocalePreferences() {
}
}

View File

@@ -63,7 +63,9 @@ public abstract class RegionalPreferenceListBasePreferenceController extends
pref.setKey(item);
pref.setOnPreferenceClickListener(clickedPref -> {
setSelected(pref);
RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(), item);
RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(),
item.equals(RegionalPreferencesDataUtils.DEFAULT_VALUE)
? null : item);
mMetricsFeatureProvider.action(mContext, getMetricsActionKey());
return true;
});

View File

@@ -22,6 +22,8 @@ import android.os.LocaleList;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.core.text.util.LocalePreferences;
import com.android.internal.app.LocalePicker;
import com.android.settings.R;

View File

@@ -19,6 +19,8 @@ package com.android.settings.regionalpreferences;
import android.content.Context;
import android.provider.Settings;
import androidx.core.text.util.LocalePreferences;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;

View File

@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
@@ -45,6 +46,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -53,6 +55,7 @@ import android.util.ArraySet;
import com.android.settings.TestUtils;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import org.junit.After;
@@ -89,6 +92,7 @@ public final class BatteryBackupHelperTest {
private PrintWriter mPrintWriter;
private StringWriter mStringWriter;
private BatteryBackupHelper mBatteryBackupHelper;
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@Mock
private PackageManager mPackageManager;
@@ -112,6 +116,8 @@ public final class BatteryBackupHelperTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mPowerUsageFeatureProvider =
FakeFeatureFactory.setupForTest().powerUsageFeatureProvider;
mContext = spy(RuntimeEnvironment.application);
mStringWriter = new StringWriter();
mPrintWriter = new PrintWriter(mStringWriter);
@@ -136,19 +142,11 @@ public final class BatteryBackupHelperTest {
}
@Test
public void performBackup_nullPowerList_notBackupPowerList() throws Exception {
doReturn(null).when(mDeviceController).getFullPowerWhitelist();
mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
}
@Test
public void performBackup_emptyPowerList_notBackupPowerList() throws Exception {
public void performBackup_emptyPowerList_backupPowerList() throws Exception {
doReturn(new String[0]).when(mDeviceController).getFullPowerWhitelist();
mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
verify(mBackupDataOutput, atLeastOnce()).writeEntityHeader(anyString(), anyInt());
}
@Test
@@ -159,34 +157,6 @@ public final class BatteryBackupHelperTest {
verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
}
@Test
public void performBackup_oneFullPowerListElement_backupFullPowerListData()
throws Exception {
final String[] fullPowerList = {"com.android.package"};
doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
final byte[] expectedBytes = fullPowerList[0].getBytes();
verify(mBackupDataOutput).writeEntityHeader(
BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
}
@Test
public void performBackup_backupFullPowerListData() throws Exception {
final String[] fullPowerList = {"com.android.package1", "com.android.package2"};
doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
final String expectedResult = fullPowerList[0] + DELIMITER + fullPowerList[1];
final byte[] expectedBytes = expectedResult.getBytes();
verify(mBackupDataOutput).writeEntityHeader(
BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
}
@Test
public void performBackup_nonOwner_ignoreAllBackupAction() throws Exception {
ShadowUserHandle.setUid(1);
@@ -283,7 +253,7 @@ public final class BatteryBackupHelperTest {
@Test
public void restoreEntity_incorrectDataKey_notReadBackupData() throws Exception {
final String incorrectDataKey = BatteryBackupHelper.KEY_FULL_POWER_LIST;
final String incorrectDataKey = "incorrect_data_key";
mockBackupData(30 /*dataSize*/, incorrectDataKey);
mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
@@ -313,6 +283,20 @@ public final class BatteryBackupHelperTest {
assertThat(TestUtils.getScheduledLevel(mContext)).isNotEqualTo(invalidScheduledLevel);
}
@Test
public void restoreEntity_verifyConfigurationOneTimeOnly() {
final int invalidScheduledLevel = 5;
TestUtils.setScheduledLevel(mContext, invalidScheduledLevel);
mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
TestUtils.setScheduledLevel(mContext, invalidScheduledLevel);
// Invoke the restoreEntity() method 2nd time.
mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
assertThat(TestUtils.getScheduledLevel(mContext))
.isEqualTo(invalidScheduledLevel);
}
@Test
public void restoreOptimizationMode_nullBytesData_skipRestore() throws Exception {
mBatteryBackupHelper.restoreOptimizationMode(new byte[0]);
@@ -358,6 +342,26 @@ public final class BatteryBackupHelperTest {
.setAppUsageState(MODE_RESTRICTED, Action.RESTORE);
}
@Test
public void performBackup_backupDeviceBuildInformation() throws Exception {
final String[] fullPowerList = {"com.android.package"};
doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
doReturn(null).when(mPowerUsageFeatureProvider).getBuildMetadata1(mContext);
final String deviceMetadata = "device.metadata.test_device";
doReturn(deviceMetadata).when(mPowerUsageFeatureProvider).getBuildMetadata2(mContext);
mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
final InOrder inOrder = inOrder(mBackupDataOutput);
verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_BRAND, Build.BRAND);
verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_PRODUCT, Build.PRODUCT);
verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_MANUFACTURER, Build.MANUFACTURER);
verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_FINGERPRINT, Build.FINGERPRINT);
inOrder.verify(mBackupDataOutput, never()).writeEntityHeader(
eq(BatteryBackupHelper.KEY_BUILD_METADATA_1), anyInt());
verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_METADATA_2, deviceMetadata);
}
private void mockUid(int uid, String packageName) throws Exception {
doReturn(uid).when(mPackageManager)
.getPackageUid(packageName, PackageManager.GET_META_DATA);
@@ -429,6 +433,13 @@ public final class BatteryBackupHelperTest {
new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3));
}
private void verifyBackupData(
InOrder inOrder, String dataKey, String dataContent) throws Exception {
final byte[] expectedBytes = dataContent.getBytes();
inOrder.verify(mBackupDataOutput).writeEntityHeader(dataKey, expectedBytes.length);
inOrder.verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
}
@Implements(UserHandle.class)
public static class ShadowUserHandle {
// Sets the default as thte OWNER role.

View File

@@ -39,6 +39,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -152,6 +153,7 @@ public class FaceUpdaterTest {
verify(mSafetyCenterManagerWrapper, never()).isEnabled(any());
}
@Ignore("b/282413778")
@Test
public void enroll_secondVersion_onEnrollmentCallbacks_triggerGivenCallback() {
ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
@@ -180,6 +182,7 @@ public class FaceUpdaterTest {
.onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
}
@Ignore("b/282413778")
@Test
public void enroll_secondVersion_onEnrollmentSuccess_invokedInteractionWithSafetyCenter() {
ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
@@ -201,6 +204,7 @@ public class FaceUpdaterTest {
verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
}
@Ignore("b/282413778")
@Test
public void enroll_secondVersion_onEnrollmentNotYetFinished_didntInvokeInteractionWithSafetyCenter() {
ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =

View File

@@ -56,11 +56,39 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
private GraphicsDriverEnableAngleAsSystemDriverController mController;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
// Signal to wait for SystemProperty values changed
private class PropertyChangeSignal {
private CountDownLatch mCountDownLatch;
@Mock
private GraphicsDriverSystemPropertiesWrapper mSystemPropertiesMock;
private Runnable mCountDownJob;
PropertyChangeSignal() {
mCountDownLatch = new CountDownLatch(1);
mCountDownJob =
new Runnable() {
@Override
public void run() {
mCountDownLatch.countDown();
}
};
}
public Runnable getCountDownJob() {
return mCountDownJob;
}
public void wait(int timeoutInMilliSeconds) {
try {
mCountDownLatch.await(timeoutInMilliSeconds, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
}
}
@Mock private DevelopmentSettingsDashboardFragment mFragment;
@Mock private GraphicsDriverSystemPropertiesWrapper mSystemPropertiesMock;
@Before
public void setUp() {
@@ -76,18 +104,27 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
// so we can force the SystemProperties with values we need to run tests.
// 2) Override the showRebootDialog() to do nothing.
// We do not need to pop up the reboot dialog in the test.
// 3) Override the rebootDevice() to do nothing.
mController = new GraphicsDriverEnableAngleAsSystemDriverController(
mContext, mFragment, new Injector(){
@Override
public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
}) {
@Override
void showRebootDialog() {
// do nothing
}
};
mContext,
mFragment,
new Injector() {
@Override
public GraphicsDriverSystemPropertiesWrapper
createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
}) {
@Override
void showRebootDialog() {
// do nothing
}
@Override
void rebootDevice(Context context) {
// do nothing
}
};
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
@@ -99,58 +136,42 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
@Test
public void onPreferenceChange_switchOn_shouldEnableAngleAsSystemDriver() {
// Step 1: toggle the switch "Enable ANGLE" on
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test onPreferenceChange(true) updates the persist.graphics.egl to "angle"
PropertyChangeSignal propertyChangeSignal = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal.getCountDownJob());
mController.onPreferenceChange(mPreference, true);
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
propertyChangeSignal.wait(100);
// Step 2: verify results
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
// Step 3: clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
SystemProperties.removeChangeCallback(propertyChangeSignal.getCountDownJob());
}
@Test
public void onPreferenceChange_switchOff_shouldDisableAngleAsSystemDriver() {
// Step 1: toggle the switch "Enable ANGLE" off
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test onPreferenceChange(false) updates the persist.graphics.egl to ""
PropertyChangeSignal propertyChangeSignal = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal.getCountDownJob());
mController.onPreferenceChange(mPreference, false);
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
propertyChangeSignal.wait(100);
// Step 2: verify results
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// Step 3: clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
SystemProperties.removeChangeCallback(propertyChangeSignal.getCountDownJob());
}
@Test
@@ -162,8 +183,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
@Test
public void updateState_angleNotSupported_PreferenceShouldNotBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("");
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@@ -191,8 +211,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
updateState_angleSupported_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("true");
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn("");
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any())).thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@@ -218,28 +237,18 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
// Test that onDeveloperOptionSwitchDisabled,
// persist.graphics.egl updates to ""
mController.onDeveloperOptionsSwitchDisabled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
propertyChangeSignal1.wait(100);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
}
@Test
@@ -256,70 +265,217 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
@Test
public void onRebootCancelled_ToggleSwitchFromOnToOff() {
// Step 1: Toggle the "Enable ANGLE" switch on
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, true);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Test that if the current persist.graphics.egl is "angle",
// when reboot is cancelled, persist.graphics.egl is changed back to "",
// and switch is set to unchecked.
// Step 2: Cancel reboot
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(ANGLE_DRIVER_SUFFIX);
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootCancelled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify results
// 1) Test that persist.graphics.egl is changed back to "".
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// 2) Test that the switch is set to unchecked.
assertThat(mPreference.isChecked()).isFalse();
// Done with the test, remove the callback.
SystemProperties.removeChangeCallback(countDown);
// Step 4: Clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
@Test
public void onRebootCancelled_ToggleSwitchFromOffToOn() {
// Step 1: Toggle off the switch "Enable ANGLE"
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, false);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Test that if the current persist.graphics.egl is "",
// when reboot is cancelled, persist.graphics.egl is changed back to "angle",
// and switch is set to checked.
// Step 2: Cancel reboot
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn("");
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootCancelled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify results
// 1) Test that persist.graphics.egl is changed back to "ANGLE"
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
// 2) Test that the switch is set to checked
assertThat(mPreference.isChecked()).isTrue();
// Step 4: Clean up
// Done with the test, remove the callback.
SystemProperties.removeChangeCallback(countDown);
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
@Test
public void onRebootDialogDismissed_ToggleSwitchFromOnToOff() {
// Step 1: Toggle on the switch "Enable ANGLE"
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, true);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Step 2: Dismiss the reboot dialog
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify results
// 1) Test that persist.graphics.egl is changed back to "".
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// 2) Test that the switch is set to unchecked.
assertThat(mPreference.isChecked()).isFalse();
// Step 4: Clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
@Test
public void onRebootDialogDismissed_ToggleSwitchFromOffToOn() {
// Step 1: Toggle on the switch "Enable ANGLE"
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, false);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Step 2: Dismiss the reboot dialog
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify results
// 1) Test that persist.graphics.egl is changed back to "ANGLE"
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
// 2) Test that the switch is set to checked
assertThat(mPreference.isChecked()).isTrue();
// Step 4: Clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
@Test
public void onRebootDialogConfirmed_ToggleSwitchOnRemainsOn() {
// Step 1: Toggle on the switch "Enable ANGLE"
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, true);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Step 2: Confirm reboot
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootConfirmed(mContext);
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify Results
// Test that persist.graphics.egl remains to be "ANGLE"
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
// Step 4: Clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
@Test
public void onRebootDialogConfirmed_ToggleSwitchOffRemainsOff() {
// Step 1: Toggle off the switch "Enable ANGLE"
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
PropertyChangeSignal propertyChangeSignal1 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal1.getCountDownJob());
mController.onPreferenceChange(mPreference, false);
// Block the following code execution until the "persist.graphics.egl" property value is
// changed.
propertyChangeSignal1.wait(100);
// Step 2: Confirm reboot
PropertyChangeSignal propertyChangeSignal2 = new PropertyChangeSignal();
SystemProperties.addChangeCallback(propertyChangeSignal2.getCountDownJob());
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL));
mController.onRebootConfirmed(mContext);
mController.onRebootDialogDismissed();
// Block the following code execution until the "persist.graphics.egl" property valye is
// changed.
propertyChangeSignal2.wait(100);
// Step 3: Verify Results
// Test that persist.graphics.egl remains to be ""
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// Step 4: Clean up
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(propertyChangeSignal1.getCountDownJob());
SystemProperties.removeChangeCallback(propertyChangeSignal2.getCountDownJob());
}
}

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import android.os.LocaleList;
import android.provider.Settings;
import androidx.core.text.util.LocalePreferences;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.app.LocalePicker;