Snap for 10147226 from 174bd2ab74 to udc-release
Change-Id: Idb0a9f28c69f39df0600fb58d5f2b144e791f149
This commit is contained in:
@@ -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">
|
||||
|
||||
14
TEST_MAPPING
14
TEST_MAPPING
@@ -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": [
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ public class ClonedAppsPreferenceController extends BasePreferenceController
|
||||
}
|
||||
|
||||
private void updatePreferenceSummary() {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
new AsyncTask<Void, Void, Integer[]>() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user