Merge "[Regional Preference] Set numbering system when select it" into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5904282..ff4096f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -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">
diff --git a/res/drawable/button_border_selected.xml b/res/drawable/button_border_selected.xml
index 0cd4aa5..1402380 100644
--- a/res/drawable/button_border_selected.xml
+++ b/res/drawable/button_border_selected.xml
@@ -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"/>
diff --git a/res/drawable/button_border_unselected.xml b/res/drawable/button_border_unselected.xml
index 2c2ef3d..d0ce75b 100644
--- a/res/drawable/button_border_unselected.xml
+++ b/res/drawable/button_border_unselected.xml
@@ -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>
diff --git a/res/drawable/checkbox_circle_shape.xml b/res/drawable/checkbox_circle_shape.xml
index 68c5a2e..51a567c 100644
--- a/res/drawable/checkbox_circle_shape.xml
+++ b/res/drawable/checkbox_circle_shape.xml
@@ -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>
\ No newline at end of file
+ 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>
\ No newline at end of file
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
index b748f94..5819774 100644
--- a/res/layout/choose_lock_password.xml
+++ b/res/layout/choose_lock_password.xml
@@ -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"
diff --git a/res/layout/homepage_preference.xml b/res/layout/homepage_preference.xml
index 18ecdcf..f0b1b71 100644
--- a/res/layout/homepage_preference.xml
+++ b/res/layout/homepage_preference.xml
@@ -60,6 +60,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 405960b..1f3ba2a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -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>
@@ -10158,7 +10158,9 @@
<string name="financed_privacy_restrictions_removed">All restrictions are removed from the device</string>
<!-- Label explaining that the app installed by credit provider can be uninstalled. [CHAR LIMIT=60]-->
<string name="financed_privacy_uninstall_creditor_app">You can uninstall the creditor app</string>
-
+ <!-- Title of setting on security settings screen on a device provisioned by Device Lock. This will take the user to a screen in Device Lock with information about what a device provider can control and their impact on the user's privacy. Shown on Device Lock provisioned devices only. [CHAR LIMIT=NONE] -->
+ <!-- TODO(b/282040794): Update the title -->
+ <string name="device_lock_info">Device Lock</string>
<!-- Strings for displaying which applications were set as default for specific actions. -->
<!-- Title for the apps that have been set as default handlers of camera-related intents. [CHAR LIMIT=30] -->
<string name="default_camera_app_title">{count, plural,
diff --git a/res/values/themes.xml b/res/values/themes.xml
index eeba1c7..8f13279 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -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>
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index d8af009..73241b7 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -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>
diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml
index 5fce68f..1a9d788 100644
--- a/res/xml/more_security_privacy_settings.xml
+++ b/res/xml/more_security_privacy_settings.xml
@@ -146,6 +146,13 @@
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
+ <Preference
+ android:key="device_lock_info"
+ android:title="@string/device_lock_info"
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.devicelock.DeviceLockPreferenceController">
+ <intent android:action="com.android.devicelockcontroller.action.DEVICE_INFO_SETTINGS"/>
+ </Preference>
</PreferenceCategory>
<Preference
diff --git a/res/xml/security_advanced_settings.xml b/res/xml/security_advanced_settings.xml
index 9856e84..8223f50 100644
--- a/res/xml/security_advanced_settings.xml
+++ b/res/xml/security_advanced_settings.xml
@@ -58,6 +58,13 @@
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
+ <Preference
+ android:key="device_lock_info"
+ android:title="@string/device_lock_info"
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.devicelock.DeviceLockPreferenceController">
+ <intent android:action="com.android.devicelockcontroller.action.DEVICE_INFO_SETTINGS"/>
+ </Preference>
</PreferenceCategory>
<Preference
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 2fb4af4..b3f3f7d 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -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
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index 07a737d..80d3947 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -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 @@
@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;
}
}
diff --git a/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java b/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
index 586980c..ccfa9c8 100644
--- a/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
+++ b/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
@@ -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 @@
@Override
public int getAvailabilityStatus() {
return mAppFeatureProvider.isLongBackgroundTaskPermissionToggleSupported()
- ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index d0fb16a..5dabb7a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -69,6 +69,7 @@
private static final String ENABLE_DUAL_MODE_AUDIO =
"persist.bluetooth.enable_dual_mode_audio";
+ private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
private LocalBluetoothManager mManager;
private LocalBluetoothProfileManager mProfileManager;
@@ -99,7 +100,9 @@
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
mIsLeAudioToggleEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false)
+ || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
+ CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
// Call refresh here even though it will get called later in onResume, to avoid the
// list of switches appearing to "pop" into the page.
refresh();
diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
index 0945f0d..a54c594 100644
--- a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
@@ -39,6 +39,7 @@
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
+ private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
@VisibleForTesting
@@ -87,8 +88,12 @@
final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+ final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
- ((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled);
+ mPreference.setEnabled(!leAudioEnabledByDefault);
+ ((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled
+ || leAudioEnabledByDefault);
}
@Override
diff --git a/src/com/android/settings/development/RebootConfirmationDialogFragment.java b/src/com/android/settings/development/RebootConfirmationDialogFragment.java
index 2fa0747..45c3697 100644
--- a/src/com/android/settings/development/RebootConfirmationDialogFragment.java
+++ b/src/com/android/settings/development/RebootConfirmationDialogFragment.java
@@ -28,11 +28,9 @@
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 @@
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 @@
}
}
- 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 @@
mHost.onRebootCancelled();
}
}
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ mHost.onRebootDialogDismissed();
+ }
}
diff --git a/src/com/android/settings/development/RebootConfirmationDialogHost.java b/src/com/android/settings/development/RebootConfirmationDialogHost.java
index 65ffbed..1be25a7 100644
--- a/src/com/android/settings/development/RebootConfirmationDialogHost.java
+++ b/src/com/android/settings/development/RebootConfirmationDialogHost.java
@@ -20,22 +20,20 @@
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() {}
}
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
index 04252fa..1a065a9 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
@@ -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.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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
((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 @@
// 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;
+ }
}
diff --git a/src/com/android/settings/devicelock/DeviceLockPreferenceController.java b/src/com/android/settings/devicelock/DeviceLockPreferenceController.java
new file mode 100644
index 0000000..4b6fe88
--- /dev/null
+++ b/src/com/android/settings/devicelock/DeviceLockPreferenceController.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.devicelock;
+
+import android.content.Context;
+import android.devicelock.DeviceLockManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * The PreferenceController that manages the Device Lock entry preference.
+ */
+public final class DeviceLockPreferenceController extends BasePreferenceController {
+
+ private static final String TAG = "DeviceLockPreferenceController";
+
+ private final DeviceLockManager mDeviceLockManager;
+
+ public DeviceLockPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mDeviceLockManager = mContext.getSystemService(DeviceLockManager.class);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // TODO(b/282856378): make this entry searchable
+ return AVAILABLE_UNSEARCHABLE;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ mDeviceLockManager.getKioskApps(mContext.getMainExecutor(),
+ result -> {
+ // if kiosk apps present on the device, the device is provisioned by Device Lock
+ boolean isDeviceProvisionedByDeviceLock = result != null && !result.isEmpty();
+ Log.d(TAG, "Set preference visibility to " + isDeviceProvisionedByDeviceLock);
+ // TODO(b/282179089): find alternatives instead of calling setVisible
+ preference.setVisible(isDeviceProvisionedByDeviceLock);
+ });
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index eb4bbf6..66ffc90 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -25,17 +25,20 @@
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,9 +52,19 @@
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 = ":";
@@ -69,7 +82,13 @@
@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,33 +102,50 @@
return;
}
final List<String> allowlistedApps = getFullPowerList();
- if (allowlistedApps != null) {
- backupOptimizationMode(data, allowlistedApps);
+ 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
@@ -220,6 +256,23 @@
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(
@@ -299,8 +352,33 @@
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);
@@ -308,5 +386,6 @@
} catch (IOException e) {
Log.e(TAG, "writeBackupData() is failed for " + dataKey, e);
}
+ Log.d(TAG, String.format("backup:%s:%s", dataKey, dataContent));
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 9f30473..0b0e243 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -18,6 +18,7 @@
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 @@
* 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);
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index d65c212..1d0ba18 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -22,6 +22,7 @@
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 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;
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
index 214b01a..b041003 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
@@ -18,7 +18,9 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.os.BadParcelableException;
import android.os.Bundle;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -142,14 +144,26 @@
}
public void restoreInstanceState(Bundle bundle) {
- if (bundle != null) {
+ if (bundle == null) {
+ return;
+ }
+ try {
List<BatteryTip> batteryTips = bundle.getParcelableArrayList(KEY_BATTERY_TIPS);
updateBatteryTips(batteryTips);
+ } catch (BadParcelableException e) {
+ Log.e(TAG, "failed to invoke restoreInstanceState()", e);
}
}
- public void saveInstanceState(Bundle outState) {
- outState.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips);
+ public void saveInstanceState(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ try {
+ bundle.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips);
+ } catch (BadParcelableException e) {
+ Log.e(TAG, "failed to invoke saveInstanceState()", e);
+ }
}
public boolean needUpdate() {
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
index 823f5bb..1e39fff 100644
--- a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
@@ -63,7 +63,9 @@
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;
});
diff --git a/tests/robotests/src/com/android/settings/devicelock/DeviceLockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/devicelock/DeviceLockPreferenceControllerTest.java
new file mode 100644
index 0000000..3176969
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/devicelock/DeviceLockPreferenceControllerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.devicelock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.devicelock.DeviceLockManager;
+import android.os.OutcomeReceiver;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Collections;
+import java.util.Map;
+
+@RunWith(RobolectricTestRunner.class)
+public final class DeviceLockPreferenceControllerTest {
+
+ private static final String TEST_PREFERENCE_KEY = "KEY";
+ private static final Map<Integer, String> TEST_KIOSK_APPS = Map.of(0, "test");
+ @Mock
+ private DeviceLockManager mDeviceLockManager;
+ @Captor
+ private ArgumentCaptor<OutcomeReceiver<Map<Integer, String>, Exception>>
+ mOutcomeReceiverArgumentCaptor;
+ private DeviceLockPreferenceController mController;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+ Context context = spy(mContext);
+ when(context.getSystemService(DeviceLockManager.class)).thenReturn(mDeviceLockManager);
+ mController = new DeviceLockPreferenceController(context, TEST_PREFERENCE_KEY);
+ }
+
+ @Test
+ public void testUpdateState_preferenceBecomesInvisibleIfNoKioskAppsPresent() {
+ Preference preference = new Preference(mContext, null, 0, 0);
+ preference.setVisible(true);
+
+ mController.updateState(preference);
+
+ verify(mDeviceLockManager).getKioskApps(any(), mOutcomeReceiverArgumentCaptor.capture());
+ OutcomeReceiver<Map<Integer, String>, Exception> outcomeReceiver =
+ mOutcomeReceiverArgumentCaptor.getValue();
+
+ outcomeReceiver.onResult(Collections.emptyMap());
+ assertThat(preference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState_preferenceBecomesVisibleIfKioskAppsPresent() {
+ Preference preference = new Preference(mContext, null, 0, 0);
+ preference.setVisible(false);
+
+ mController.updateState(preference);
+
+ verify(mDeviceLockManager).getKioskApps(any(), mOutcomeReceiverArgumentCaptor.capture());
+ OutcomeReceiver<Map<Integer, String>, Exception> outcomeReceiver =
+ mOutcomeReceiverArgumentCaptor.getValue();
+
+ outcomeReceiver.onResult(TEST_KIOSK_APPS);
+ assertThat(preference.isVisible()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index a800fdb..b8c72ee 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -28,6 +28,7 @@
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.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 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 @@
private PrintWriter mPrintWriter;
private StringWriter mStringWriter;
private BatteryBackupHelper mBatteryBackupHelper;
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@Mock
private PackageManager mPackageManager;
@@ -112,6 +116,8 @@
@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 @@
}
@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
@@ -286,6 +284,20 @@
}
@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]);
verifyNoInteractions(mBatteryOptimizeUtils);
@@ -330,6 +342,26 @@
.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);
@@ -401,6 +433,13 @@
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.
diff --git a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
index 3f85535..c23292a 100644
--- a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
+++ b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
@@ -56,11 +56,39 @@
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 @@
// 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 @@
@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 @@
@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 @@
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 @@
// 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 @@
@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());
+ }
}