Snap for 11811809 from 93fe16fc25 to 24Q3-release
Change-Id: I538b38b49b8f31ea11d61480b4c6777708f44eaa
This commit is contained in:
@@ -240,6 +240,28 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".development.Enable16KBootReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".development.PageAgnosticNotificationService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:permission="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
|
||||||
|
<activity android:name=".development.PageAgnosticWarningActivity"
|
||||||
|
android:enabled="true"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"/>
|
||||||
|
|
||||||
<activity android:name=".SubSettings"
|
<activity android:name=".SubSettings"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:theme="@style/Theme.SubSettings"
|
android:theme="@style/Theme.SubSettings"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ java_aconfig_library {
|
|||||||
aconfig_declarations {
|
aconfig_declarations {
|
||||||
name: "factory_reset_flags",
|
name: "factory_reset_flags",
|
||||||
package: "com.android.settings.factory_reset",
|
package: "com.android.settings.factory_reset",
|
||||||
container: "system",
|
container: "system_ext",
|
||||||
srcs: ["factory_reset/*.aconfig"],
|
srcs: ["factory_reset/*.aconfig"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ java_aconfig_library {
|
|||||||
aconfig_declarations {
|
aconfig_declarations {
|
||||||
name: "media_drm_flags",
|
name: "media_drm_flags",
|
||||||
package: "com.android.settings.media_drm",
|
package: "com.android.settings.media_drm",
|
||||||
container: "system",
|
container: "system_ext",
|
||||||
srcs: ["media_drm/*.aconfig"],
|
srcs: ["media_drm/*.aconfig"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ java_aconfig_library {
|
|||||||
aconfig_declarations {
|
aconfig_declarations {
|
||||||
name: "accessibility_flags",
|
name: "accessibility_flags",
|
||||||
package: "com.android.settings.accessibility",
|
package: "com.android.settings.accessibility",
|
||||||
container: "system",
|
container: "system_ext",
|
||||||
srcs: ["accessibility/*.aconfig"],
|
srcs: ["accessibility/*.aconfig"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ java_aconfig_library {
|
|||||||
aconfig_declarations {
|
aconfig_declarations {
|
||||||
name: "development_settings_flags",
|
name: "development_settings_flags",
|
||||||
package: "com.android.settings.development",
|
package: "com.android.settings.development",
|
||||||
container: "system",
|
container: "system_ext",
|
||||||
srcs: [
|
srcs: [
|
||||||
"development/**/*.aconfig",
|
"development/**/*.aconfig",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package: "com.android.settings.accessibility"
|
package: "com.android.settings.accessibility"
|
||||||
container: "system"
|
container: "system_ext"
|
||||||
|
|
||||||
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
|
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package: "com.android.settings.development"
|
package: "com.android.settings.development"
|
||||||
container: "system"
|
container: "system_ext"
|
||||||
|
|
||||||
flag {
|
flag {
|
||||||
name: "a2dp_offload_codec_extensibility_settings"
|
name: "a2dp_offload_codec_extensibility_settings"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package: "com.android.settings.factory_reset"
|
package: "com.android.settings.factory_reset"
|
||||||
container: "system"
|
container: "system_ext"
|
||||||
|
|
||||||
flag {
|
flag {
|
||||||
name: "enable_factory_reset_wizard"
|
name: "enable_factory_reset_wizard"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package: "com.android.settings.media_drm"
|
package: "com.android.settings.media_drm"
|
||||||
container: "system"
|
container: "system_ext"
|
||||||
|
|
||||||
flag {
|
flag {
|
||||||
name: "force_l3_enabled"
|
name: "force_l3_enabled"
|
||||||
|
|||||||
18
res/color-night-v35/settings_two_pane_background_color.xml
Normal file
18
res/color-night-v35/settings_two_pane_background_color.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2024 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="@android:color/system_surface_dim_dark" />
|
||||||
|
</selector>
|
||||||
18
res/color-v35/settings_two_pane_background_color.xml
Normal file
18
res/color-v35/settings_two_pane_background_color.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2024 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="@android:color/system_surface_dim_light" />
|
||||||
|
</selector>
|
||||||
@@ -14,5 +14,5 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?android:attr/colorAccent"/>
|
<item android:color="@color/settingslib_materialColorPrimary"/>
|
||||||
</selector>
|
</selector>
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<solid android:color="?androidprv:attr/materialColorPrimaryContainer" />
|
<solid android:color="@color/settingslib_materialColorPrimaryContainer" />
|
||||||
<corners android:radius="@dimen/battery_hints_chip_corner_radius" />
|
<corners android:radius="@dimen/battery_hints_chip_corner_radius" />
|
||||||
</shape>
|
</shape>
|
||||||
@@ -17,6 +17,6 @@
|
|||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<solid android:color="@color/settingslib_dialog_background" />
|
<solid android:color="@color/settingslib_materialColorSurfaceBright" />
|
||||||
<corners android:radius="@dimen/battery_tips_card_corner_radius_normal" />
|
<corners android:radius="@dimen/battery_tips_card_corner_radius_normal" />
|
||||||
</shape>
|
</shape>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:textColor="?android:attr/textColorPrimary" />
|
android:textColor="@color/settingslib_materialColorOnSurface" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="16dp"
|
||||||
android:text="@string/battery_tips_card_action_button"
|
android:text="@string/battery_tips_card_action_button"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
|
||||||
android:textColor="@color/power_anomaly_primary_button_text_color"
|
android:textColor="@color/settingslib_materialColorOnPrimary"
|
||||||
app:backgroundTint="@color/color_accent_selector" />
|
app:backgroundTint="@color/color_accent_selector" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -38,6 +38,6 @@
|
|||||||
android:paddingHorizontal="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
|
||||||
android:textColor="?androidprv:attr/materialColorOnSurface"/>
|
android:textColor="@color/settingslib_materialColorOnSurface"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
<!-- Power anomaly color for icons, button and text -->
|
<!-- Power anomaly color for icons, button and text -->
|
||||||
<color name="power_anomaly_app_warning_hint_color">#FDD663</color>
|
<color name="power_anomaly_app_warning_hint_color">#FDD663</color>
|
||||||
<color name="power_anomaly_primary_button_text_color">#2E3300</color>
|
|
||||||
|
|
||||||
<!-- UDFPS colors -->
|
<!-- UDFPS colors -->
|
||||||
<color name="udfps_enroll_icon">#7DA7F1</color>
|
<color name="udfps_enroll_icon">#7DA7F1</color>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
|
<style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
|
||||||
<item name="colorPrimary">@*android:color/primary_device_default_settings</item>
|
<item name="colorPrimary">@*android:color/primary_device_default_settings</item>
|
||||||
<item name="colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
|
<item name="colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
|
||||||
<item name="android:colorBackground">?android:attr/colorPrimaryDark</item>
|
<item name="android:colorBackground">@android:color/system_surface_container_dark</item>
|
||||||
<!-- Homepage should follow device default design, the values is same as device default theme.-->
|
<!-- Homepage should follow device default design, the values is same as device default theme.-->
|
||||||
<item name="android:navigationBarColor">@android:color/black</item>
|
<item name="android:navigationBarColor">@android:color/black</item>
|
||||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
|
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
|
||||||
|
|
||||||
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
|
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
|
||||||
<item name="colorAccent">@*android:color/accent_device_default_dark</item>
|
<item name="colorAccent">@android:color/system_primary_dark</item>
|
||||||
<item name="android:colorError">@color/settings_dialog_colorError</item>
|
<item name="android:colorError">@color/settings_dialog_colorError</item>
|
||||||
<item name="android:colorBackground">@*android:color/surface_dark</item>
|
<item name="android:colorBackground">@android:color/system_surface_container_high_dark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Panel.Material" parent="Theme.Panel" >
|
<style name="Theme.Panel.Material" parent="Theme.Panel" >
|
||||||
|
|||||||
@@ -171,9 +171,8 @@
|
|||||||
<!-- Icon tint color for battery usage system icon -->
|
<!-- Icon tint color for battery usage system icon -->
|
||||||
<color name="battery_usage_system_icon_color">?android:attr/textColorPrimary</color>
|
<color name="battery_usage_system_icon_color">?android:attr/textColorPrimary</color>
|
||||||
|
|
||||||
<!-- Power anomaly color for icons, button and text -->
|
<!-- Power anomaly color for icons, button -->
|
||||||
<color name="power_anomaly_app_warning_hint_color">#D56E0C</color>
|
<color name="power_anomaly_app_warning_hint_color">#D56E0C</color>
|
||||||
<color name="power_anomaly_primary_button_text_color">#FFFFFF</color>
|
|
||||||
|
|
||||||
<!-- UDFPS colors -->
|
<!-- UDFPS colors -->
|
||||||
<color name="udfps_enroll_icon">#699FF3</color>
|
<color name="udfps_enroll_icon">#699FF3</color>
|
||||||
|
|||||||
@@ -115,9 +115,9 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
|
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
|
||||||
<item name="colorAccent">@*android:color/accent_device_default_light</item>
|
<item name="colorAccent">@android:color/system_primary_light</item>
|
||||||
<item name="android:colorError">@color/settings_dialog_colorError</item>
|
<item name="android:colorError">@color/settings_dialog_colorError</item>
|
||||||
<item name="android:colorBackground">@*android:color/surface_light</item>
|
<item name="android:colorBackground">@android:color/system_surface_container_high_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.AlertDialog" parent="Theme.AlertDialog.Base">
|
<style name="Theme.AlertDialog" parent="Theme.AlertDialog.Base">
|
||||||
@@ -204,6 +204,7 @@
|
|||||||
<!-- Homepage should follow device default design, the values is same as device default theme.-->
|
<!-- Homepage should follow device default design, the values is same as device default theme.-->
|
||||||
<item name="android:navigationBarColor">@android:color/white</item>
|
<item name="android:navigationBarColor">@android:color/white</item>
|
||||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||||
|
<item name="android:colorBackground">@android:color/system_surface_container_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Settings.Home.NoAnimation">
|
<style name="Theme.Settings.Home.NoAnimation">
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ menghanli@google.com #{LAST_RESORT_SUGGESTION}
|
|||||||
cipson@google.com #{LAST_RESORT_SUGGESTION}
|
cipson@google.com #{LAST_RESORT_SUGGESTION}
|
||||||
|
|
||||||
# Partner-team files
|
# Partner-team files
|
||||||
per-file HapticFeedbackIntensityPreferenceController.java = michaelwr@google.com
|
per-file HapticFeedbackIntensityPreferenceController.java = file:platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
|
||||||
per-file *Vibration* = michaelwr@google.com
|
per-file *Vibration* = file:platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
|
||||||
|
|||||||
@@ -83,11 +83,14 @@ public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setChecked(boolean isChecked) {
|
public boolean setChecked(boolean isChecked) {
|
||||||
|
// The main switch change can be triggered by both the user click and the
|
||||||
|
// SettingsMainSwitchPreferenceController state change. Make sure we only do it once.
|
||||||
|
boolean wasChecked = isChecked();
|
||||||
boolean success = Settings.System.putInt(mContext.getContentResolver(),
|
boolean success = Settings.System.putInt(mContext.getContentResolver(),
|
||||||
VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY,
|
VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY,
|
||||||
isChecked ? ON : OFF);
|
isChecked ? ON : OFF);
|
||||||
|
|
||||||
if (success && isChecked) {
|
if (success && !wasChecked && isChecked) {
|
||||||
// Play a haptic as preview for the main toggle only when touch feedback is enabled.
|
// Play a haptic as preview for the main toggle only when touch feedback is enabled.
|
||||||
VibrationPreferenceConfig.playVibrationPreview(
|
VibrationPreferenceConfig.playVibrationPreview(
|
||||||
mVibrator, VibrationAttributes.USAGE_TOUCH);
|
mVibrator, VibrationAttributes.USAGE_TOUCH);
|
||||||
|
|||||||
@@ -182,9 +182,11 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
|||||||
refreshPreferenceController(QuickSettingsShortcutOptionController.class);
|
refreshPreferenceController(QuickSettingsShortcutOptionController.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getContext() != null) {
|
||||||
PreferredShortcuts.updatePreferredShortcutsFromSettings(
|
PreferredShortcuts.updatePreferredShortcutsFromSettings(
|
||||||
getContext(), mShortcutTargets);
|
getContext(), mShortcutTargets);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
registerSettingsObserver();
|
registerSettingsObserver();
|
||||||
@@ -388,7 +390,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
|||||||
private void refreshPreferenceController(
|
private void refreshPreferenceController(
|
||||||
Class<? extends AbstractPreferenceController> controllerClass) {
|
Class<? extends AbstractPreferenceController> controllerClass) {
|
||||||
AbstractPreferenceController controller = use(controllerClass);
|
AbstractPreferenceController controller = use(controllerClass);
|
||||||
if (controller != null) {
|
if (controller != null && getPreferenceScreen() != null) {
|
||||||
controller.displayPreference(getPreferenceScreen());
|
controller.displayPreference(getPreferenceScreen());
|
||||||
if (!TextUtils.isEmpty(controller.getPreferenceKey())) {
|
if (!TextUtils.isEmpty(controller.getPreferenceKey())) {
|
||||||
controller.updateState(findPreference(controller.getPreferenceKey()));
|
controller.updateState(findPreference(controller.getPreferenceKey()));
|
||||||
|
|||||||
@@ -87,6 +87,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
implements LifecycleObserver {
|
implements LifecycleObserver {
|
||||||
public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
|
public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
|
||||||
|
|
||||||
|
private static final String TAG = "CredentialManagerPreferenceController";
|
||||||
|
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
||||||
|
private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
|
||||||
|
private static final int MAX_SELECTABLE_PROVIDERS = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In the settings logic we should hide the list of additional credman providers if there is no
|
* In the settings logic we should hide the list of additional credman providers if there is no
|
||||||
* provider selected at the top. The current logic relies on checking whether the autofill
|
* provider selected at the top. The current logic relies on checking whether the autofill
|
||||||
@@ -95,11 +100,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
*/
|
*/
|
||||||
public static final String AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER = "credential-provider";
|
public static final String AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER = "credential-provider";
|
||||||
|
|
||||||
private static final String TAG = "CredentialManagerPreferenceController";
|
|
||||||
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
|
||||||
private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
|
|
||||||
private static final int MAX_SELECTABLE_PROVIDERS = 5;
|
|
||||||
|
|
||||||
private final PackageManager mPm;
|
private final PackageManager mPm;
|
||||||
private final List<CredentialProviderInfo> mServices;
|
private final List<CredentialProviderInfo> mServices;
|
||||||
private final Set<String> mEnabledPackageNames;
|
private final Set<String> mEnabledPackageNames;
|
||||||
@@ -522,7 +522,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
// empty string.
|
// empty string.
|
||||||
String selectedAutofillProvider =
|
String selectedAutofillProvider =
|
||||||
DefaultCombinedPicker.getSelectedAutofillProvider(mContext, getUser());
|
DefaultCombinedPicker.getSelectedAutofillProvider(mContext, getUser());
|
||||||
if (TextUtils.equals(
|
String credentialAutofillService = "";
|
||||||
|
if (android.service.autofill.Flags.autofillCredmanDevIntegration()) {
|
||||||
|
credentialAutofillService = getCredentialAutofillService(mContext, TAG);
|
||||||
|
}
|
||||||
|
if (TextUtils.equals(selectedAutofillProvider, credentialAutofillService)
|
||||||
|
|| TextUtils.equals(
|
||||||
selectedAutofillProvider, AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER)) {
|
selectedAutofillProvider, AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER)) {
|
||||||
selectedAutofillProvider = "";
|
selectedAutofillProvider = "";
|
||||||
}
|
}
|
||||||
@@ -679,6 +684,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
return (enabledAdditionalProviderCount + 1) >= MAX_SELECTABLE_PROVIDERS;
|
return (enabledAdditionalProviderCount + 1) >= MAX_SELECTABLE_PROVIDERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the credential autofill service component name. */
|
||||||
|
public static String getCredentialAutofillService(Context context, String tag) {
|
||||||
|
try {
|
||||||
|
return context.getResources().getString(
|
||||||
|
com.android.internal.R.string.config_defaultCredentialManagerAutofillService);
|
||||||
|
} catch (Resources.NotFoundException e) {
|
||||||
|
Log.e(tag, "Failed to find credential autofill service.", e);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
private CombiPreference addProviderPreference(
|
private CombiPreference addProviderPreference(
|
||||||
@NonNull Context prefContext,
|
@NonNull Context prefContext,
|
||||||
@NonNull CharSequence title,
|
@NonNull CharSequence title,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.applications.credentials;
|
package com.android.settings.applications.credentials;
|
||||||
|
|
||||||
|
import static com.android.settings.applications.credentials.CredentialManagerPreferenceController.getCredentialAutofillService;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -463,11 +465,15 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
private void setProviders(String autofillProvider, List<String> primaryCredManProviders) {
|
private void setProviders(String autofillProvider, List<String> primaryCredManProviders) {
|
||||||
if (TextUtils.isEmpty(autofillProvider)) {
|
if (TextUtils.isEmpty(autofillProvider)) {
|
||||||
if (primaryCredManProviders.size() > 0) {
|
if (primaryCredManProviders.size() > 0) {
|
||||||
|
if (android.service.autofill.Flags.autofillCredmanDevIntegration()) {
|
||||||
|
autofillProvider = getCredentialAutofillService(getContext(), TAG);
|
||||||
|
} else {
|
||||||
autofillProvider =
|
autofillProvider =
|
||||||
CredentialManagerPreferenceController
|
CredentialManagerPreferenceController
|
||||||
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
|
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Settings.Secure.putStringForUser(
|
Settings.Secure.putStringForUser(
|
||||||
getContext().getContentResolver(), AUTOFILL_SETTING, autofillProvider, getUser());
|
getContext().getContentResolver(), AUTOFILL_SETTING, autofillProvider, getUser());
|
||||||
|
|||||||
@@ -595,6 +595,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
if (Utils.isMonkeyRunning()) {
|
if (Utils.isMonkeyRunning()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disabling developer options in page-agnostic mode isn't supported as device isn't in
|
||||||
|
// production state
|
||||||
|
if (Enable16kUtils.isPageAgnosticModeOn(getContext())) {
|
||||||
|
Enable16kUtils.showPageAgnosticWarning(getContext());
|
||||||
|
onDisableDevelopmentOptionsRejected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false);
|
DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false);
|
||||||
final SystemPropPoker poker = SystemPropPoker.getInstance();
|
final SystemPropPoker poker = SystemPropPoker.getInstance();
|
||||||
poker.blockPokes();
|
poker.blockPokes();
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public class Enable16KBootReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (!Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do nothing if device is not in page-agnostic mode
|
||||||
|
if (!Enable16kUtils.isPageAgnosticModeOn(context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start a service to post persistent notification
|
||||||
|
Intent startNotificationIntent = new Intent(context, PageAgnosticNotificationService.class);
|
||||||
|
context.startServiceAsUser(startNotificationIntent, UserHandle.SYSTEM);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,10 +16,15 @@
|
|||||||
|
|
||||||
package com.android.settings.development;
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -60,7 +65,10 @@ public class Enable16KOemUnlockDialog extends InstrumentedDialogFragment
|
|||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
return new AlertDialog.Builder(getActivity())
|
return new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(R.string.confirm_oem_unlock_for_16k_title)
|
.setTitle(R.string.confirm_oem_unlock_for_16k_title)
|
||||||
.setMessage(R.string.confirm_oem_unlock_for_16k_text)
|
.setMessage(
|
||||||
|
Html.fromHtml(
|
||||||
|
getString(R.string.confirm_oem_unlock_for_16k_text),
|
||||||
|
FROM_HTML_MODE_COMPACT))
|
||||||
.setPositiveButton(android.R.string.ok, this /* onClickListener */)
|
.setPositiveButton(android.R.string.ok, this /* onClickListener */)
|
||||||
.create();
|
.create();
|
||||||
}
|
}
|
||||||
@@ -74,4 +82,11 @@ public class Enable16KOemUnlockDialog extends InstrumentedDialogFragment
|
|||||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||||
super.onDismiss(dialog);
|
super.onDismiss(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
((TextView) getDialog().findViewById(android.R.id.message))
|
||||||
|
.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,11 @@ import android.os.ParcelFileDescriptor;
|
|||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.RecoverySystem;
|
import android.os.RecoverySystem;
|
||||||
import android.os.SystemProperties;
|
|
||||||
import android.os.SystemUpdateManager;
|
import android.os.SystemUpdateManager;
|
||||||
import android.os.UpdateEngine;
|
import android.os.UpdateEngine;
|
||||||
import android.os.UpdateEngineStable;
|
import android.os.UpdateEngineStable;
|
||||||
import android.os.UpdateEngineStableCallback;
|
import android.os.UpdateEngineStableCallback;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.os.UserManager;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.oemlock.OemLockManager;
|
|
||||||
import android.system.Os;
|
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -59,7 +53,6 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@@ -80,10 +73,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
private static final String TAG = "Enable16kPages";
|
private static final String TAG = "Enable16kPages";
|
||||||
private static final String REBOOT_REASON = "toggle16k";
|
private static final String REBOOT_REASON = "toggle16k";
|
||||||
private static final String ENABLE_16K_PAGES = "enable_16k_pages";
|
private static final String ENABLE_16K_PAGES = "enable_16k_pages";
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static final String DEV_OPTION_PROPERTY = "ro.product.build.16k_page.enabled";
|
|
||||||
|
|
||||||
private static final int ENABLE_4K_PAGE_SIZE = 0;
|
private static final int ENABLE_4K_PAGE_SIZE = 0;
|
||||||
private static final int ENABLE_16K_PAGE_SIZE = 1;
|
private static final int ENABLE_16K_PAGE_SIZE = 1;
|
||||||
|
|
||||||
@@ -97,9 +86,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
private static final int OFFSET_TO_FILE_NAME = 30;
|
private static final int OFFSET_TO_FILE_NAME = 30;
|
||||||
public static final String EXPERIMENTAL_UPDATE_TITLE = "Android 16K Kernel Experimental Update";
|
public static final String EXPERIMENTAL_UPDATE_TITLE = "Android 16K Kernel Experimental Update";
|
||||||
|
|
||||||
private static final long PAGE_SIZE = Os.sysconf(OsConstants._SC_PAGESIZE);
|
|
||||||
private static final int PAGE_SIZE_16KB = 16 * 1024;
|
|
||||||
|
|
||||||
private @NonNull DevelopmentSettingsDashboardFragment mFragment;
|
private @NonNull DevelopmentSettingsDashboardFragment mFragment;
|
||||||
private boolean mEnable16k;
|
private boolean mEnable16k;
|
||||||
|
|
||||||
@@ -112,12 +98,12 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
@NonNull Context context, @NonNull DevelopmentSettingsDashboardFragment fragment) {
|
@NonNull Context context, @NonNull DevelopmentSettingsDashboardFragment fragment) {
|
||||||
super(context);
|
super(context);
|
||||||
this.mFragment = fragment;
|
this.mFragment = fragment;
|
||||||
mEnable16k = (PAGE_SIZE == PAGE_SIZE_16KB);
|
mEnable16k = Enable16kUtils.isUsing16kbPages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable() {
|
||||||
return SystemProperties.getBoolean(DEV_OPTION_PROPERTY, false);
|
return Enable16kUtils.is16KbToggleAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,12 +115,12 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
mEnable16k = (Boolean) newValue;
|
mEnable16k = (Boolean) newValue;
|
||||||
// Prompt user to do oem unlock first
|
// Prompt user to do oem unlock first
|
||||||
if (!isDeviceOEMUnlocked()) {
|
if (!Enable16kUtils.isDeviceOEMUnlocked(mContext)) {
|
||||||
Enable16KOemUnlockDialog.show(mFragment);
|
Enable16KOemUnlockDialog.show(mFragment);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDataf2fs()) {
|
if (!Enable16kUtils.isDataExt4()) {
|
||||||
EnableExt4WarningDialog.show(mFragment, this);
|
EnableExt4WarningDialog.show(mFragment, this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -145,7 +131,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference) {
|
public void updateState(Preference preference) {
|
||||||
int defaultOptionValue =
|
int defaultOptionValue =
|
||||||
PAGE_SIZE == PAGE_SIZE_16KB ? ENABLE_16K_PAGE_SIZE : ENABLE_4K_PAGE_SIZE;
|
Enable16kUtils.isUsing16kbPages() ? ENABLE_16K_PAGE_SIZE : ENABLE_4K_PAGE_SIZE;
|
||||||
final int optionValue =
|
final int optionValue =
|
||||||
Settings.Global.getInt(
|
Settings.Global.getInt(
|
||||||
mContext.getContentResolver(),
|
mContext.getContentResolver(),
|
||||||
@@ -169,7 +155,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
@Override
|
@Override
|
||||||
protected void onDeveloperOptionsSwitchEnabled() {
|
protected void onDeveloperOptionsSwitchEnabled() {
|
||||||
int currentStatus =
|
int currentStatus =
|
||||||
PAGE_SIZE == PAGE_SIZE_16KB ? ENABLE_16K_PAGE_SIZE : ENABLE_4K_PAGE_SIZE;
|
Enable16kUtils.isUsing16kbPages() ? ENABLE_16K_PAGE_SIZE : ENABLE_4K_PAGE_SIZE;
|
||||||
Settings.Global.putInt(
|
Settings.Global.putInt(
|
||||||
mContext.getContentResolver(), Settings.Global.ENABLE_16K_PAGES, currentStatus);
|
mContext.getContentResolver(), Settings.Global.ENABLE_16K_PAGES, currentStatus);
|
||||||
}
|
}
|
||||||
@@ -432,51 +418,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
return infoBundle;
|
return infoBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataf2fs() {
|
|
||||||
try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
final String[] fields = line.split(" ");
|
|
||||||
final String partition = fields[1];
|
|
||||||
final String fsType = fields[2];
|
|
||||||
if (partition.equals("/data") && fsType.equals("f2fs")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Failed to read /proc/mounts");
|
|
||||||
displayToast(mContext.getString(R.string.format_ext4_failure_toast));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDeviceOEMUnlocked() {
|
|
||||||
// OEM unlock is checked for bootloader, carrier and user. Check all three to ensure
|
|
||||||
// that device is unlocked and it is also allowed by user as well as carrier
|
|
||||||
final OemLockManager oemLockManager = mContext.getSystemService(OemLockManager.class);
|
|
||||||
final UserManager userManager = mContext.getSystemService(UserManager.class);
|
|
||||||
if (oemLockManager == null || userManager == null) {
|
|
||||||
Log.e(TAG, "Required services not found on device to check for OEM unlock state.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If either of device or carrier is not allowed to unlock, return false
|
|
||||||
if (!oemLockManager.isDeviceOemUnlocked()
|
|
||||||
|| !oemLockManager.isOemUnlockAllowedByCarrier()) {
|
|
||||||
Log.e(TAG, "Device is not OEM unlocked or it is not allowed by carrier");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final UserHandle userHandle = UserHandle.of(UserHandle.myUserId());
|
|
||||||
if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, userHandle)) {
|
|
||||||
Log.e(TAG, "Factory reset is not allowed for user.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if BOARD_16K_OTA_MOVE_VENDOR, OTAs will be present on the /vendor partition
|
// if BOARD_16K_OTA_MOVE_VENDOR, OTAs will be present on the /vendor partition
|
||||||
private File getOtaFile() throws FileNotFoundException {
|
private File getOtaFile() throws FileNotFoundException {
|
||||||
String otaPath = mEnable16k ? OTA_16K_PATH : OTA_4K_PATH;
|
String otaPath = mEnable16k ? OTA_16K_PATH : OTA_4K_PATH;
|
||||||
|
|||||||
129
src/com/android/settings/development/Enable16kUtils.java
Normal file
129
src/com/android/settings/development/Enable16kUtils.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.service.oemlock.OemLockManager;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Enable16kUtils {
|
||||||
|
private static final long PAGE_SIZE = Os.sysconf(OsConstants._SC_PAGESIZE);
|
||||||
|
private static final int PAGE_SIZE_16KB = 16 * 1024;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String DEV_OPTION_PROPERTY = "ro.product.build.16k_page.enabled";
|
||||||
|
|
||||||
|
private static final String TAG = "Enable16kUtils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context uses context to retrieve OEM unlock info
|
||||||
|
* @return true if device is OEM unlocked and factory reset is allowed for user.
|
||||||
|
*/
|
||||||
|
public static boolean isDeviceOEMUnlocked(@NonNull Context context) {
|
||||||
|
// OEM unlock is checked for bootloader, carrier and user. Check all three to ensure
|
||||||
|
// that device is unlocked and it is also allowed by user as well as carrier
|
||||||
|
final OemLockManager oemLockManager = context.getSystemService(OemLockManager.class);
|
||||||
|
final UserManager userManager = context.getSystemService(UserManager.class);
|
||||||
|
if (oemLockManager == null || userManager == null) {
|
||||||
|
Log.e(TAG, "Required services not found on device to check for OEM unlock state.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If either of device or carrier is not allowed to unlock, return false
|
||||||
|
if (!oemLockManager.isDeviceOemUnlocked()) {
|
||||||
|
Log.e(TAG, "Device is not OEM unlocked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final UserHandle userHandle = UserHandle.of(UserHandle.myUserId());
|
||||||
|
if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, userHandle)) {
|
||||||
|
Log.e(TAG, "Factory reset is not allowed for user.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if /data partition is ext4
|
||||||
|
*/
|
||||||
|
public static boolean isDataExt4() {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
Log.i(TAG, line);
|
||||||
|
final String[] fields = line.split(" ");
|
||||||
|
final String partition = fields[1];
|
||||||
|
final String fsType = fields[2];
|
||||||
|
if (partition.equals("/data") && fsType.equals("ext4")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to read /proc/mounts");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return returns true if 16KB developer option is available for the device.
|
||||||
|
*/
|
||||||
|
public static boolean is16KbToggleAvailable() {
|
||||||
|
return SystemProperties.getBoolean(DEV_OPTION_PROPERTY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16kB page-agnostic mode requires /data to be ext4, ro.product.build.16k_page.enabled for
|
||||||
|
* device and Device OEM unlocked.
|
||||||
|
*
|
||||||
|
* @param context is needed to query OEM unlock state
|
||||||
|
* @return true if device is in page-agnostic mode.
|
||||||
|
*/
|
||||||
|
public static boolean isPageAgnosticModeOn(@NonNull Context context) {
|
||||||
|
return is16KbToggleAvailable() && isDeviceOEMUnlocked(context) && isDataExt4();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return returns true if current page size is 16KB
|
||||||
|
*/
|
||||||
|
public static boolean isUsing16kbPages() {
|
||||||
|
return PAGE_SIZE == PAGE_SIZE_16KB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show page-agnostic mode warning dialog to user
|
||||||
|
* @param context to start activity
|
||||||
|
*/
|
||||||
|
public static void showPageAgnosticWarning(@NonNull Context context) {
|
||||||
|
Intent intent = new Intent(context, PageAgnosticWarningActivity.class);
|
||||||
|
context.startActivityAsUser(intent, UserHandle.SYSTEM);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
public class PageAgnosticNotificationService extends Service {
|
||||||
|
|
||||||
|
private static final String NOTIFICATION_CHANNEL_ID =
|
||||||
|
"com.android.settings.development.PageAgnosticNotificationService";
|
||||||
|
private static final int NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
|
static final int DISABLE_UPDATES_SETTING = 1;
|
||||||
|
|
||||||
|
private NotificationManager mNotificationManager;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(@NonNull Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a notification channel to post persistent notification
|
||||||
|
private void createNotificationChannel() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(
|
||||||
|
NOTIFICATION_CHANNEL_ID,
|
||||||
|
getString(R.string.page_agnostic_notification_channel_name),
|
||||||
|
NotificationManager.IMPORTANCE_HIGH);
|
||||||
|
mNotificationManager = getSystemService(NotificationManager.class);
|
||||||
|
if (mNotificationManager != null) {
|
||||||
|
mNotificationManager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
createNotificationChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification buildNotification() {
|
||||||
|
// Get the title and text according to page size
|
||||||
|
boolean isIn16kbMode = Enable16kUtils.isUsing16kbPages();
|
||||||
|
String title =
|
||||||
|
isIn16kbMode
|
||||||
|
? getString(R.string.page_agnostic_16k_pages_title)
|
||||||
|
: getString(R.string.page_agnostic_4k_pages_title);
|
||||||
|
String text =
|
||||||
|
isIn16kbMode
|
||||||
|
? getString(R.string.page_agnostic_16k_pages_text_short)
|
||||||
|
: getString(R.string.page_agnostic_4k_pages_text_short);
|
||||||
|
|
||||||
|
Intent notifyIntent = new Intent(this, PageAgnosticWarningActivity.class);
|
||||||
|
// Set the Activity to start in a new, empty task.
|
||||||
|
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
|
||||||
|
// Create the PendingIntent.
|
||||||
|
PendingIntent notifyPendingIntent =
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
notifyIntent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||||
|
|
||||||
|
Notification.Action action =
|
||||||
|
new Notification.Action.Builder(
|
||||||
|
R.drawable.empty_icon,
|
||||||
|
getString(R.string.page_agnostic_notification_action),
|
||||||
|
notifyPendingIntent)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Notification.Builder builder =
|
||||||
|
new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(text)
|
||||||
|
.setOngoing(true)
|
||||||
|
.setSmallIcon(R.drawable.ic_settings_24dp)
|
||||||
|
.setStyle(new Notification.BigTextStyle().bigText(text))
|
||||||
|
.setContentIntent(notifyPendingIntent)
|
||||||
|
.addAction(action);
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableAutomaticUpdates() {
|
||||||
|
final int currentState =
|
||||||
|
Settings.Global.getInt(
|
||||||
|
getApplicationContext().getContentResolver(),
|
||||||
|
Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
|
||||||
|
0 /* default */);
|
||||||
|
// 0 means enabled, 1 means disabled
|
||||||
|
if (currentState == 0) {
|
||||||
|
// automatic updates are enabled, disable them
|
||||||
|
Settings.Global.putInt(
|
||||||
|
getApplicationContext().getContentResolver(),
|
||||||
|
Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
|
||||||
|
DISABLE_UPDATES_SETTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
|
||||||
|
Notification notification = buildNotification();
|
||||||
|
if (mNotificationManager != null) {
|
||||||
|
mNotificationManager.notify(NOTIFICATION_ID, notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No updates should be allowed in page-agnostic mode
|
||||||
|
disableAutomaticUpdates();
|
||||||
|
return Service.START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
public class PageAgnosticWarningActivity extends Activity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle bundle) {
|
||||||
|
super.onCreate(bundle);
|
||||||
|
|
||||||
|
String title =
|
||||||
|
Enable16kUtils.isUsing16kbPages()
|
||||||
|
? getString(R.string.page_agnostic_16k_pages_title)
|
||||||
|
: getString(R.string.page_agnostic_4k_pages_title);
|
||||||
|
|
||||||
|
String warningText =
|
||||||
|
Enable16kUtils.isUsing16kbPages()
|
||||||
|
? getString(R.string.page_agnostic_16k_pages_text)
|
||||||
|
: getString(R.string.page_agnostic_4k_pages_text);
|
||||||
|
showWarningDialog(title, warningText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create warning dialog and make links clickable
|
||||||
|
private void showWarningDialog(String title, String warningText) {
|
||||||
|
|
||||||
|
AlertDialog dialog =
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(Html.fromHtml(warningText, Html.FROM_HTML_MODE_COMPACT))
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(
|
||||||
|
android.R.string.ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(
|
||||||
|
@NonNull DialogInterface dialog, int which) {
|
||||||
|
dialog.cancel();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
dialog.show();
|
||||||
|
|
||||||
|
((TextView) dialog.findViewById(android.R.id.message))
|
||||||
|
.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,6 +78,21 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence generateLabel(BatteryInfo info) {
|
private CharSequence generateLabel(BatteryInfo info) {
|
||||||
|
if (Utils.containsIncompatibleChargers(mContext, TAG)) {
|
||||||
|
return mContext.getString(
|
||||||
|
com.android.settingslib.R.string.battery_info_status_not_charging);
|
||||||
|
}
|
||||||
|
if (BatteryUtils.isBatteryDefenderOn(info)) {
|
||||||
|
return mContext.getString(
|
||||||
|
com.android.settingslib.R.string.battery_info_status_charging_on_hold);
|
||||||
|
}
|
||||||
|
if (info.remainingLabel == null
|
||||||
|
|| info.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
|
||||||
|
return info.statusLabel;
|
||||||
|
}
|
||||||
|
if (mBatterySettingsFeatureProvider.isChargingOptimizationMode(mContext)) {
|
||||||
|
return info.remainingLabel;
|
||||||
|
}
|
||||||
if (info.pluggedStatus == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
|
if (info.pluggedStatus == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
|
||||||
final CharSequence wirelessChargingLabel =
|
final CharSequence wirelessChargingLabel =
|
||||||
mBatterySettingsFeatureProvider.getWirelessChargingLabel(mContext, info);
|
mBatterySettingsFeatureProvider.getWirelessChargingLabel(mContext, info);
|
||||||
@@ -85,18 +100,7 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
|||||||
return wirelessChargingLabel;
|
return wirelessChargingLabel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (info.statusLabel != null && !info.discharging) {
|
||||||
if (Utils.containsIncompatibleChargers(mContext, TAG)) {
|
|
||||||
return mContext.getString(
|
|
||||||
com.android.settingslib.R.string.battery_info_status_not_charging);
|
|
||||||
} else if (BatteryUtils.isBatteryDefenderOn(info)) {
|
|
||||||
return mContext.getString(
|
|
||||||
com.android.settingslib.R.string.battery_info_status_charging_on_hold);
|
|
||||||
} else if (info.remainingLabel == null
|
|
||||||
|| info.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
|
|
||||||
// Present status only if no remaining time or status anomalous
|
|
||||||
return info.statusLabel;
|
|
||||||
} else if (info.statusLabel != null && !info.discharging) {
|
|
||||||
// Charging state
|
// Charging state
|
||||||
if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
|
if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
|
||||||
return info.isFastCharging
|
return info.isFastCharging
|
||||||
|
|||||||
@@ -319,6 +319,12 @@ public class BatteryInfo {
|
|||||||
info.isFastCharging =
|
info.isFastCharging =
|
||||||
BatteryStatus.getChargingSpeed(context, batteryBroadcast)
|
BatteryStatus.getChargingSpeed(context, batteryBroadcast)
|
||||||
== BatteryStatus.CHARGING_FAST;
|
== BatteryStatus.CHARGING_FAST;
|
||||||
|
if (info.isBatteryDefender) {
|
||||||
|
info.isBatteryDefender =
|
||||||
|
FeatureFactory.getFeatureFactory()
|
||||||
|
.getPowerUsageFeatureProvider()
|
||||||
|
.isBatteryDefend(info);
|
||||||
|
}
|
||||||
if (!info.mCharging) {
|
if (!info.mCharging) {
|
||||||
updateBatteryInfoDischarging(context, shortString, estimate, info);
|
updateBatteryInfoDischarging(context, shortString, estimate, info);
|
||||||
} else {
|
} else {
|
||||||
@@ -388,9 +394,10 @@ public class BatteryInfo {
|
|||||||
&& status != BatteryManager.BATTERY_STATUS_FULL
|
&& status != BatteryManager.BATTERY_STATUS_FULL
|
||||||
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|
||||||
|| dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
|
|| dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
|
||||||
|
final BatterySettingsFeatureProvider featureProvider =
|
||||||
|
FeatureFactory.getFeatureFactory().getBatterySettingsFeatureProvider();
|
||||||
// Battery is charging to full
|
// Battery is charging to full
|
||||||
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
|
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
|
||||||
|
|
||||||
int resId = getChargingDurationResId(info.isFastCharging);
|
int resId = getChargingDurationResId(info.isFastCharging);
|
||||||
info.remainingLabel =
|
info.remainingLabel =
|
||||||
chargeTimeMs <= 0
|
chargeTimeMs <= 0
|
||||||
@@ -400,7 +407,8 @@ public class BatteryInfo {
|
|||||||
chargeTimeMs,
|
chargeTimeMs,
|
||||||
info.isFastCharging,
|
info.isFastCharging,
|
||||||
info.pluggedStatus,
|
info.pluggedStatus,
|
||||||
currentTimeMs);
|
currentTimeMs,
|
||||||
|
featureProvider);
|
||||||
|
|
||||||
info.chargeLabel =
|
info.chargeLabel =
|
||||||
chargeTimeMs <= 0
|
chargeTimeMs <= 0
|
||||||
@@ -411,7 +419,8 @@ public class BatteryInfo {
|
|||||||
info.batteryPercentString,
|
info.batteryPercentString,
|
||||||
chargeTimeMs,
|
chargeTimeMs,
|
||||||
info.isFastCharging,
|
info.isFastCharging,
|
||||||
currentTimeMs);
|
currentTimeMs,
|
||||||
|
featureProvider);
|
||||||
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
|
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
|
||||||
// Dock defender will be triggered in the future, charging will be optimized.
|
// Dock defender will be triggered in the future, charging will be optimized.
|
||||||
info.chargeLabel =
|
info.chargeLabel =
|
||||||
@@ -436,10 +445,17 @@ public class BatteryInfo {
|
|||||||
long chargeRemainingTimeMs,
|
long chargeRemainingTimeMs,
|
||||||
boolean isFastCharging,
|
boolean isFastCharging,
|
||||||
int pluggedStatus,
|
int pluggedStatus,
|
||||||
long currentTimeMs) {
|
long currentTimeMs,
|
||||||
|
BatterySettingsFeatureProvider featureProvider) {
|
||||||
|
if (featureProvider.isChargingOptimizationMode(context)) {
|
||||||
|
final CharSequence chargingOptimizationRemainingLabel =
|
||||||
|
featureProvider.getChargingOptimizationRemainingLabel(
|
||||||
|
context, chargeRemainingTimeMs, currentTimeMs);
|
||||||
|
if (chargingOptimizationRemainingLabel != null) {
|
||||||
|
return chargingOptimizationRemainingLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (pluggedStatus == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
|
if (pluggedStatus == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
|
||||||
BatterySettingsFeatureProvider featureProvider =
|
|
||||||
FeatureFactory.getFeatureFactory().getBatterySettingsFeatureProvider();
|
|
||||||
final CharSequence wirelessChargingRemainingLabel =
|
final CharSequence wirelessChargingRemainingLabel =
|
||||||
featureProvider.getWirelessChargingRemainingLabel(
|
featureProvider.getWirelessChargingRemainingLabel(
|
||||||
context, chargeRemainingTimeMs, currentTimeMs);
|
context, chargeRemainingTimeMs, currentTimeMs);
|
||||||
@@ -472,7 +488,16 @@ public class BatteryInfo {
|
|||||||
String batteryPercentString,
|
String batteryPercentString,
|
||||||
long chargeTimeMs,
|
long chargeTimeMs,
|
||||||
boolean isFastCharging,
|
boolean isFastCharging,
|
||||||
long currentTimeMs) {
|
long currentTimeMs,
|
||||||
|
BatterySettingsFeatureProvider featureProvider) {
|
||||||
|
if (featureProvider.isChargingOptimizationMode(context)) {
|
||||||
|
final CharSequence chargingOptimizationChargeLabel =
|
||||||
|
featureProvider.getChargingOptimizationChargeLabel(
|
||||||
|
context, batteryPercentString, chargeTimeMs, currentTimeMs);
|
||||||
|
if (chargingOptimizationChargeLabel != null) {
|
||||||
|
return chargingOptimizationChargeLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
|
if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
|
||||||
var timeString =
|
var timeString =
|
||||||
PowerUtil.getTargetTimeShortString(context, chargeTimeMs, currentTimeMs);
|
PowerUtil.getTargetTimeShortString(context, chargeTimeMs, currentTimeMs);
|
||||||
|
|||||||
@@ -53,4 +53,20 @@ public interface BatterySettingsFeatureProvider {
|
|||||||
@Nullable
|
@Nullable
|
||||||
CharSequence getWirelessChargingRemainingLabel(
|
CharSequence getWirelessChargingRemainingLabel(
|
||||||
@NonNull Context context, long remainingTimeMs, long currentTimeMs);
|
@NonNull Context context, long remainingTimeMs, long currentTimeMs);
|
||||||
|
|
||||||
|
/** Return true if it's in the charging optimization mode. */
|
||||||
|
boolean isChargingOptimizationMode(@NonNull Context context);
|
||||||
|
|
||||||
|
/** Return a charging remaining time label for charging optimization mode. */
|
||||||
|
@Nullable
|
||||||
|
CharSequence getChargingOptimizationRemainingLabel(
|
||||||
|
@NonNull Context context, long chargeRemainingTimeMs, long currentTimeMs);
|
||||||
|
|
||||||
|
/** Return a charge label for charging optimization mode. */
|
||||||
|
@Nullable
|
||||||
|
CharSequence getChargingOptimizationChargeLabel(
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull String batteryPercentageString,
|
||||||
|
long chargeRemainingTimeMs,
|
||||||
|
long currentTimeMs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,4 +67,26 @@ public class BatterySettingsFeatureProviderImpl implements BatterySettingsFeatur
|
|||||||
@NonNull Context context, long remainingTimeMs, long currentTimeMs) {
|
@NonNull Context context, long remainingTimeMs, long currentTimeMs) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChargingOptimizationMode(@NonNull Context context) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public CharSequence getChargingOptimizationRemainingLabel(
|
||||||
|
@NonNull Context context, long chargeRemainingTimeMs, long currentTimeMs) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public CharSequence getChargingOptimizationChargeLabel(
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull String batteryPercentageString,
|
||||||
|
long chargeRemainingTimeMs,
|
||||||
|
long currentTimeMs) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MobileNetworkListFragment : DashboardFragment() {
|
|||||||
super.onCreate(icicle)
|
super.onCreate(icicle)
|
||||||
|
|
||||||
if (Flags.isDualSimOnboardingEnabled()) {
|
if (Flags.isDualSimOnboardingEnabled()) {
|
||||||
context?.startSpaActivity(NetworkCellularGroupProvider.name);
|
context?.startSpaActivity(NetworkCellularGroupProvider.fileName)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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.network.helper;
|
|
||||||
|
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.telephony.UiccCardInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a Callable class which queries valid card ID for eSIM
|
|
||||||
*/
|
|
||||||
public class QueryEsimCardId implements Callable<AtomicIntegerArray> {
|
|
||||||
private static final String TAG = "QueryEsimCardId";
|
|
||||||
|
|
||||||
private TelephonyManager mTelephonyManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor of class
|
|
||||||
* @param TelephonyManager
|
|
||||||
*/
|
|
||||||
public QueryEsimCardId(TelephonyManager telephonyManager) {
|
|
||||||
mTelephonyManager = telephonyManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Callable
|
|
||||||
* @return card ID(s) in AtomicIntegerArray
|
|
||||||
*/
|
|
||||||
public AtomicIntegerArray call() {
|
|
||||||
List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
|
|
||||||
if (cardInfos == null) {
|
|
||||||
return new AtomicIntegerArray(0);
|
|
||||||
}
|
|
||||||
return new AtomicIntegerArray(cardInfos.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.filter(cardInfo -> (!cardInfo.isRemovable() && (cardInfo.getCardId() >= 0)))
|
|
||||||
.mapToInt(UiccCardInfo::getCardId)
|
|
||||||
.toArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,6 @@ import android.util.Log;
|
|||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settings.network.helper.SubscriptionAnnotation;
|
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -103,15 +102,6 @@ public class SelectableSubscriptions implements Callable<List<SubscriptionAnnota
|
|||||||
TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
|
TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// query in background thread
|
|
||||||
Future<AtomicIntegerArray> eSimCardId =
|
|
||||||
ThreadUtils.postOnBackgroundThread(new QueryEsimCardId(telMgr));
|
|
||||||
|
|
||||||
// query in background thread
|
|
||||||
Future<AtomicIntegerArray> simSlotIndex =
|
|
||||||
ThreadUtils.postOnBackgroundThread(
|
|
||||||
new QuerySimSlotIndex(telMgr, true, true));
|
|
||||||
|
|
||||||
// query in background thread
|
// query in background thread
|
||||||
Future<AtomicIntegerArray> activeSimSlotIndex =
|
Future<AtomicIntegerArray> activeSimSlotIndex =
|
||||||
ThreadUtils.postOnBackgroundThread(
|
ThreadUtils.postOnBackgroundThread(
|
||||||
@@ -120,16 +110,13 @@ public class SelectableSubscriptions implements Callable<List<SubscriptionAnnota
|
|||||||
List<SubscriptionInfo> subInfoList = mSubscriptions.get();
|
List<SubscriptionInfo> subInfoList = mSubscriptions.get();
|
||||||
|
|
||||||
// wait for result from background thread
|
// wait for result from background thread
|
||||||
List<Integer> eSimCardIdList = atomicToList(eSimCardId.get());
|
|
||||||
List<Integer> simSlotIndexList = atomicToList(simSlotIndex.get());
|
|
||||||
List<Integer> activeSimSlotIndexList = atomicToList(activeSimSlotIndex.get());
|
List<Integer> activeSimSlotIndexList = atomicToList(activeSimSlotIndex.get());
|
||||||
|
|
||||||
// build a list of SubscriptionAnnotation
|
// build a list of SubscriptionAnnotation
|
||||||
return IntStream.range(0, subInfoList.size())
|
return IntStream.range(0, subInfoList.size())
|
||||||
.mapToObj(subInfoIndex ->
|
.mapToObj(subInfoIndex ->
|
||||||
new SubscriptionAnnotation.Builder(subInfoList, subInfoIndex))
|
new SubscriptionAnnotation.Builder(subInfoList, subInfoIndex))
|
||||||
.map(annoBdr -> annoBdr.build(mContext,
|
.map(annoBdr -> annoBdr.build(mContext, activeSimSlotIndexList))
|
||||||
eSimCardIdList, simSlotIndexList, activeSimSlotIndexList))
|
|
||||||
.filter(mFilter)
|
.filter(mFilter)
|
||||||
.collect(Collectors.collectingAndThen(Collectors.toList(), mFinisher));
|
.collect(Collectors.collectingAndThen(Collectors.toList(), mFinisher));
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
package com.android.settings.network.helper;
|
package com.android.settings.network.helper;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.ParcelUuid;
|
|
||||||
import android.telephony.SubscriptionInfo;
|
import android.telephony.SubscriptionInfo;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
|
|
||||||
@@ -35,14 +34,11 @@ public class SubscriptionAnnotation {
|
|||||||
private static final String TAG = "SubscriptionAnnotation";
|
private static final String TAG = "SubscriptionAnnotation";
|
||||||
|
|
||||||
private SubscriptionInfo mSubInfo;
|
private SubscriptionInfo mSubInfo;
|
||||||
private int mOrderWithinList;
|
|
||||||
private int mType = TYPE_UNKNOWN;
|
private int mType = TYPE_UNKNOWN;
|
||||||
private boolean mIsExisted;
|
private boolean mIsExisted;
|
||||||
private boolean mIsActive;
|
private boolean mIsActive;
|
||||||
private boolean mIsAllowToDisplay;
|
private boolean mIsAllowToDisplay;
|
||||||
|
|
||||||
public static final ParcelUuid EMPTY_UUID = ParcelUuid.fromString("0-0-0-0-0");
|
|
||||||
|
|
||||||
public static final int TYPE_UNKNOWN = 0x0;
|
public static final int TYPE_UNKNOWN = 0x0;
|
||||||
public static final int TYPE_PSIM = 0x1;
|
public static final int TYPE_PSIM = 0x1;
|
||||||
public static final int TYPE_ESIM = 0x2;
|
public static final int TYPE_ESIM = 0x2;
|
||||||
@@ -52,8 +48,8 @@ public class SubscriptionAnnotation {
|
|||||||
*/
|
*/
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private List<SubscriptionInfo> mSubInfoList;
|
private final List<SubscriptionInfo> mSubInfoList;
|
||||||
private int mIndexWithinList;
|
private final int mIndexWithinList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of builder
|
* Constructor of builder
|
||||||
@@ -65,10 +61,9 @@ public class SubscriptionAnnotation {
|
|||||||
mIndexWithinList = indexWithinList;
|
mIndexWithinList = indexWithinList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionAnnotation build(Context context, List<Integer> eSimCardId,
|
public SubscriptionAnnotation build(Context context, List<Integer> activeSimSlotIndex) {
|
||||||
List<Integer> simSlotIndex, List<Integer> activeSimSlotIndex) {
|
|
||||||
return new SubscriptionAnnotation(mSubInfoList, mIndexWithinList, context,
|
return new SubscriptionAnnotation(mSubInfoList, mIndexWithinList, context,
|
||||||
eSimCardId, simSlotIndex, activeSimSlotIndex);
|
activeSimSlotIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,8 +73,7 @@ public class SubscriptionAnnotation {
|
|||||||
@Keep
|
@Keep
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected SubscriptionAnnotation(List<SubscriptionInfo> subInfoList, int subInfoIndex,
|
protected SubscriptionAnnotation(List<SubscriptionInfo> subInfoList, int subInfoIndex,
|
||||||
Context context, List<Integer> eSimCardId,
|
Context context, List<Integer> activeSimSlotIndexList) {
|
||||||
List<Integer> simSlotIndex, List<Integer> activeSimSlotIndexList) {
|
|
||||||
if ((subInfoIndex < 0) || (subInfoIndex >= subInfoList.size())) {
|
if ((subInfoIndex < 0) || (subInfoIndex >= subInfoList.size())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -88,7 +82,6 @@ public class SubscriptionAnnotation {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mOrderWithinList = subInfoIndex;
|
|
||||||
mType = mSubInfo.isEmbedded() ? TYPE_ESIM : TYPE_PSIM;
|
mType = mSubInfo.isEmbedded() ? TYPE_ESIM : TYPE_PSIM;
|
||||||
mIsExisted = true;
|
mIsExisted = true;
|
||||||
if (mType == TYPE_ESIM) {
|
if (mType == TYPE_ESIM) {
|
||||||
@@ -104,12 +97,6 @@ public class SubscriptionAnnotation {
|
|||||||
mIsAllowToDisplay = isDisplayAllowed(context);
|
mIsAllowToDisplay = isDisplayAllowed(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the index provided during construction of Builder
|
|
||||||
@Keep
|
|
||||||
public int getOrderingInList() {
|
|
||||||
return mOrderWithinList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// type of subscription
|
// type of subscription
|
||||||
@Keep
|
@Keep
|
||||||
public int getType() {
|
public int getType() {
|
||||||
@@ -141,12 +128,6 @@ public class SubscriptionAnnotation {
|
|||||||
mSubInfo.getSubscriptionId();
|
mSubInfo.getSubscriptionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// the grouping UUID
|
|
||||||
@Keep
|
|
||||||
public ParcelUuid getGroupUuid() {
|
|
||||||
return (mSubInfo == null) ? null : mSubInfo.getGroupUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the SubscriptionInfo
|
// the SubscriptionInfo
|
||||||
@Keep
|
@Keep
|
||||||
public SubscriptionInfo getSubInfo() {
|
public SubscriptionInfo getSubInfo() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
@@ -50,10 +51,14 @@ class CallStateRepository(private val context: Context) {
|
|||||||
fun isInCallFlow(): Flow<Boolean> = context.subscriptionsChangedFlow()
|
fun isInCallFlow(): Flow<Boolean> = context.subscriptionsChangedFlow()
|
||||||
.flatMapLatest {
|
.flatMapLatest {
|
||||||
val subIds = subscriptionManager.activeSubscriptionIdList
|
val subIds = subscriptionManager.activeSubscriptionIdList
|
||||||
|
if (subIds.isEmpty()) {
|
||||||
|
flowOf(false)
|
||||||
|
} else {
|
||||||
combine(subIds.map(::callStateFlow)) { states ->
|
combine(subIds.map(::callStateFlow)) { states ->
|
||||||
states.any { it != TelephonyManager.CALL_STATE_IDLE }
|
states.any { it != TelephonyManager.CALL_STATE_IDLE }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.conflate()
|
.conflate()
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.onEach { Log.d(TAG, "isInCallFlow: $it") }
|
.onEach { Log.d(TAG, "isInCallFlow: $it") }
|
||||||
|
|||||||
@@ -50,7 +50,14 @@ public class PanelFeatureProviderImpl implements PanelFeatureProvider {
|
|||||||
context.sendBroadcast(intent);
|
context.sendBroadcast(intent);
|
||||||
return null;
|
return null;
|
||||||
case Settings.Panel.ACTION_NFC:
|
case Settings.Panel.ACTION_NFC:
|
||||||
|
if (Flags.slicesRetirement()) {
|
||||||
|
Intent nfcIntent = new Intent(Settings.ACTION_NFC_SETTINGS);
|
||||||
|
nfcIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(nfcIntent);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
return NfcPanel.create(context);
|
return NfcPanel.create(context);
|
||||||
|
}
|
||||||
case Settings.Panel.ACTION_WIFI:
|
case Settings.Panel.ACTION_WIFI:
|
||||||
if (Flags.slicesRetirement()) {
|
if (Flags.slicesRetirement()) {
|
||||||
Intent wifiIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
|
Intent wifiIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ import android.telephony.UiccCardInfo;
|
|||||||
import android.telephony.UiccSlotInfo;
|
import android.telephony.UiccSlotInfo;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.flags.Flags;
|
||||||
import com.android.settings.network.SubscriptionUtil;
|
import com.android.settings.network.SubscriptionUtil;
|
||||||
import com.android.settings.network.UiccSlotUtil;
|
import com.android.settings.network.UiccSlotUtil;
|
||||||
import com.android.settings.network.UiccSlotsException;
|
import com.android.settings.network.UiccSlotsException;
|
||||||
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
|
|
||||||
import com.android.settings.sim.ChooseSimActivity;
|
import com.android.settings.sim.ChooseSimActivity;
|
||||||
import com.android.settings.sim.DsdsDialogActivity;
|
import com.android.settings.sim.DsdsDialogActivity;
|
||||||
import com.android.settings.sim.SimActivationNotifier;
|
import com.android.settings.sim.SimActivationNotifier;
|
||||||
@@ -86,11 +86,6 @@ public class SimSlotChangeHandler {
|
|||||||
throw new IllegalStateException("Cannot be called from main thread.");
|
throw new IllegalStateException("Cannot be called from main thread.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTelMgr.getActiveModemCount() > 1 && !isMultipleEnabledProfilesSupported()) {
|
|
||||||
Log.i(TAG, "The device is already in DSDS mode and no MEP. Do nothing.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UiccSlotInfo removableSlotInfo = getRemovableUiccSlotInfo();
|
UiccSlotInfo removableSlotInfo = getRemovableUiccSlotInfo();
|
||||||
if (removableSlotInfo == null) {
|
if (removableSlotInfo == null) {
|
||||||
Log.e(TAG, "Unable to find the removable slot. Do nothing.");
|
Log.e(TAG, "Unable to find the removable slot. Do nothing.");
|
||||||
@@ -112,14 +107,27 @@ public class SimSlotChangeHandler {
|
|||||||
// Sets the current removable slot state.
|
// Sets the current removable slot state.
|
||||||
setRemovableSimSlotState(mContext, currentRemovableSlotState);
|
setRemovableSimSlotState(mContext, currentRemovableSlotState);
|
||||||
|
|
||||||
if (mTelMgr.getActiveModemCount() > 1 && isMultipleEnabledProfilesSupported()) {
|
if (mTelMgr.getActiveModemCount() > 1) {
|
||||||
if(!isRemovableSimInserted) {
|
if (!Flags.isDualSimOnboardingEnabled() && !isMultipleEnabledProfilesSupported()) {
|
||||||
Log.i(TAG, "Removable Sim is not inserted in DSDS mode and MEP. Do nothing.");
|
Log.d(TAG, "The device is already in DSDS mode and no MEP. Do nothing.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!isRemovableSimInserted) {
|
||||||
|
Log.d(TAG, "Removable Sim is not inserted in DSDS mode. Do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean isDdsInvalidForNewUi = Flags.isDualSimOnboardingEnabled()
|
||||||
|
&& SubscriptionManager.getDefaultDataSubscriptionId()
|
||||||
|
== SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||||
|
if (isDdsInvalidForNewUi) {
|
||||||
|
handleRemovableSimInsertWhenDsdsAndNoDds();
|
||||||
|
} else if (isMultipleEnabledProfilesSupported()) {
|
||||||
handleRemovableSimInsertUnderDsdsMep(removableSlotInfo);
|
handleRemovableSimInsertUnderDsdsMep(removableSlotInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "the device is already in DSDS mode and have the DDS. Do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isRemovableSimInserted) {
|
if (isRemovableSimInserted) {
|
||||||
handleSimInsert(removableSlotInfo);
|
handleSimInsert(removableSlotInfo);
|
||||||
@@ -251,6 +259,17 @@ public class SimSlotChangeHandler {
|
|||||||
startChooseSimActivity(false);
|
startChooseSimActivity(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleRemovableSimInsertWhenDsdsAndNoDds() {
|
||||||
|
List<SubscriptionInfo> subscriptionInfos = getAvailableRemovableSubscription();
|
||||||
|
if (subscriptionInfos.isEmpty()) {
|
||||||
|
Log.e(TAG, "Unable to find the removable subscriptionInfo. Do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "isDdsInvalidForNewUi and getAvailableRemovableSubscription:"
|
||||||
|
+ subscriptionInfos);
|
||||||
|
startSimConfirmDialogActivity(subscriptionInfos.get(0).getSubscriptionId());
|
||||||
|
}
|
||||||
|
|
||||||
private void handleRemovableSimInsertUnderDsdsMep(UiccSlotInfo removableSlotInfo) {
|
private void handleRemovableSimInsertUnderDsdsMep(UiccSlotInfo removableSlotInfo) {
|
||||||
Log.i(TAG, "Handle Removable SIM inserted under DSDS+Mep.");
|
Log.i(TAG, "Handle Removable SIM inserted under DSDS+Mep.");
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
|
|||||||
ApnEditPageProvider,
|
ApnEditPageProvider,
|
||||||
SimOnboardingPageProvider,
|
SimOnboardingPageProvider,
|
||||||
BatteryOptimizationModeAppListPageProvider,
|
BatteryOptimizationModeAppListPageProvider,
|
||||||
NetworkCellularGroupProvider,
|
NetworkCellularGroupProvider(),
|
||||||
WifiPrivacyPageProvider,
|
WifiPrivacyPageProvider,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -94,9 +94,7 @@ class InstallUnknownAppsListModel(private val context: Context) :
|
|||||||
private fun isChangeable(
|
private fun isChangeable(
|
||||||
record: InstallUnknownAppsRecord,
|
record: InstallUnknownAppsRecord,
|
||||||
potentialPackageNames: Set<String>,
|
potentialPackageNames: Set<String>,
|
||||||
) =
|
) = record.app.packageName in potentialPackageNames
|
||||||
record.appOpsController.getMode() != MODE_DEFAULT ||
|
|
||||||
record.app.packageName in potentialPackageNames
|
|
||||||
|
|
||||||
private fun getPotentialPackageNames(userId: Int): Set<String> =
|
private fun getPotentialPackageNames(userId: Int): Set<String> =
|
||||||
AppGlobals.getPackageManager()
|
AppGlobals.getPackageManager()
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ import kotlinx.coroutines.withContext
|
|||||||
/**
|
/**
|
||||||
* Showing the sim onboarding which is the process flow of sim switching on.
|
* Showing the sim onboarding which is the process flow of sim switching on.
|
||||||
*/
|
*/
|
||||||
object NetworkCellularGroupProvider : SettingsPageProvider {
|
open class NetworkCellularGroupProvider : SettingsPageProvider {
|
||||||
override val name = "NetworkCellularGroupProvider"
|
override val name = fileName
|
||||||
|
|
||||||
private val owner = createSettingsPage()
|
private val owner = createSettingsPage()
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
|||||||
var defaultDataSubId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
var defaultDataSubId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
var nonDds: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
var nonDds: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
|
|
||||||
fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner)
|
open fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner)
|
||||||
.setUiLayoutFn {
|
.setUiLayoutFn {
|
||||||
// never using
|
// never using
|
||||||
Preference(object : PreferenceModel {
|
Preference(object : PreferenceModel {
|
||||||
@@ -123,13 +123,26 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
|||||||
nonDdsRemember.intValue = nonDds
|
nonDdsRemember.intValue = nonDds
|
||||||
}
|
}
|
||||||
|
|
||||||
PageImpl(
|
val selectableSubscriptionInfoList by subscriptionViewModel
|
||||||
|
.selectableSubscriptionInfoListFlow
|
||||||
|
.collectAsStateWithLifecycle(initialValue = emptyList())
|
||||||
|
|
||||||
|
val stringSims = stringResource(R.string.provider_network_settings_title)
|
||||||
|
RegularScaffold(title = stringSims) {
|
||||||
|
SimsSection(selectableSubscriptionInfoList)
|
||||||
|
MobileDataSectionImpl(mobileDataSelectedId,
|
||||||
|
nonDdsRemember,
|
||||||
|
)
|
||||||
|
|
||||||
|
PrimarySimSectionImpl(
|
||||||
subscriptionViewModel.selectableSubscriptionInfoListFlow,
|
subscriptionViewModel.selectableSubscriptionInfoListFlow,
|
||||||
callsSelectedId,
|
callsSelectedId,
|
||||||
textsSelectedId,
|
textsSelectedId,
|
||||||
mobileDataSelectedId,
|
mobileDataSelectedId,
|
||||||
nonDdsRemember
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OtherSection()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun allOfFlows(context: Context,
|
private fun allOfFlows(context: Context,
|
||||||
@@ -139,7 +152,7 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
|||||||
context.defaultVoiceSubscriptionFlow(),
|
context.defaultVoiceSubscriptionFlow(),
|
||||||
context.defaultSmsSubscriptionFlow(),
|
context.defaultSmsSubscriptionFlow(),
|
||||||
context.defaultDefaultDataSubscriptionFlow(),
|
context.defaultDefaultDataSubscriptionFlow(),
|
||||||
NetworkCellularGroupProvider::refreshUiStates,
|
this::refreshUiStates,
|
||||||
).flowOn(Dispatchers.Default)
|
).flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
private fun refreshUiStates(
|
private fun refreshUiStates(
|
||||||
@@ -164,32 +177,12 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
|||||||
|
|
||||||
Log.d(name, "defaultDataSubId: $defaultDataSubId, nonDds: $nonDds")
|
Log.d(name, "defaultDataSubId: $defaultDataSubId, nonDds: $nonDds")
|
||||||
}
|
}
|
||||||
}
|
@Composable
|
||||||
|
open fun OtherSection(){
|
||||||
@Composable
|
// Do nothing
|
||||||
fun PageImpl(
|
}
|
||||||
selectableSubscriptionInfoListFlow: StateFlow<List<SubscriptionInfo>>,
|
companion object {
|
||||||
defaultVoiceSubId: MutableIntState,
|
const val fileName = "NetworkCellularGroupProvider"
|
||||||
defaultSmsSubId: MutableIntState,
|
|
||||||
defaultDataSubId: MutableIntState,
|
|
||||||
nonDds: MutableIntState,
|
|
||||||
) {
|
|
||||||
val selectableSubscriptionInfoList by selectableSubscriptionInfoListFlow
|
|
||||||
.collectAsStateWithLifecycle(initialValue = emptyList())
|
|
||||||
|
|
||||||
val stringSims = stringResource(R.string.provider_network_settings_title)
|
|
||||||
RegularScaffold(title = stringSims) {
|
|
||||||
SimsSection(selectableSubscriptionInfoList)
|
|
||||||
MobileDataSectionImpl(defaultDataSubId,
|
|
||||||
nonDds,
|
|
||||||
)
|
|
||||||
|
|
||||||
PrimarySimSectionImpl(
|
|
||||||
selectableSubscriptionInfoListFlow,
|
|
||||||
defaultVoiceSubId,
|
|
||||||
defaultSmsSubId,
|
|
||||||
defaultDataSubId,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,9 +410,9 @@ suspend fun setMobileData(
|
|||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
): Unit =
|
): Unit =
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
Log.d(NetworkCellularGroupProvider.name, "setMobileData: $enabled")
|
Log.d(NetworkCellularGroupProvider.fileName, "setMobileData: $enabled")
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Log.d(NetworkCellularGroupProvider.name, "setDefaultData: [$subId]")
|
Log.d(NetworkCellularGroupProvider.fileName, "setDefaultData: [$subId]")
|
||||||
subscriptionManager?.setDefaultDataSubId(subId)
|
subscriptionManager?.setDefaultDataSubId(subId)
|
||||||
}
|
}
|
||||||
TelephonyRepository(context)
|
TelephonyRepository(context)
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public class GuestTelephonyPreferenceController extends TogglePreferenceControll
|
|||||||
super.updateState(preference);
|
super.updateState(preference);
|
||||||
mUserCaps.updateAddUserCapabilities(mContext);
|
mUserCaps.updateAddUserCapabilities(mContext);
|
||||||
preference.setVisible(isAvailable() && mUserCaps.mUserSwitcherEnabled
|
preference.setVisible(isAvailable() && mUserCaps.mUserSwitcherEnabled
|
||||||
&& mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
|
&& mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
|
||||||
|
&& !UserManager.isHeadlessSystemUserMode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
|||||||
if (!Utils.isVoiceCapable(context)) { // no telephony
|
if (!Utils.isVoiceCapable(context)) { // no telephony
|
||||||
removePreference(KEY_ENABLE_TELEPHONY);
|
removePreference(KEY_ENABLE_TELEPHONY);
|
||||||
}
|
}
|
||||||
if (mUserInfo.isMain()) {
|
if (mUserInfo.isMain() || UserManager.isHeadlessSystemUserMode()) {
|
||||||
removePreference(KEY_ENABLE_TELEPHONY);
|
removePreference(KEY_ENABLE_TELEPHONY);
|
||||||
}
|
}
|
||||||
if (mUserInfo.isRestricted()) {
|
if (mUserInfo.isRestricted()) {
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ public class Enable16kPagesPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onSystemPropertyDisabled_shouldDisablePreference() {
|
public void onSystemPropertyDisabled_shouldDisablePreference() {
|
||||||
SystemProperties.set(Enable16kPagesPreferenceController.DEV_OPTION_PROPERTY, "false");
|
SystemProperties.set(Enable16kUtils.DEV_OPTION_PROPERTY, "false");
|
||||||
assertThat(mController.isAvailable()).isEqualTo(false);
|
assertThat(mController.isAvailable()).isEqualTo(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onSystemPropertyEnabled_shouldEnablePreference() {
|
public void onSystemPropertyEnabled_shouldEnablePreference() {
|
||||||
SystemProperties.set(Enable16kPagesPreferenceController.DEV_OPTION_PROPERTY, "true");
|
SystemProperties.set(Enable16kUtils.DEV_OPTION_PROPERTY, "true");
|
||||||
assertThat(mController.isAvailable()).isEqualTo(true);
|
assertThat(mController.isAvailable()).isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
@@ -307,6 +308,9 @@ public class BatteryInfoTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getBatteryInfo_chargingWithDefender_updateChargeLabel() {
|
public void getBatteryInfo_chargingWithDefender_updateChargeLabel() {
|
||||||
doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs();
|
doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs();
|
||||||
|
doReturn(true)
|
||||||
|
.when(mFeatureFactory.powerUsageFeatureProvider)
|
||||||
|
.isBatteryDefend(any(BatteryInfo.class));
|
||||||
mChargingBatteryBroadcast.putExtra(
|
mChargingBatteryBroadcast.putExtra(
|
||||||
BatteryManager.EXTRA_CHARGING_STATUS,
|
BatteryManager.EXTRA_CHARGING_STATUS,
|
||||||
BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
|
BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
|
||||||
@@ -363,6 +367,9 @@ public class BatteryInfoTest {
|
|||||||
.when(mBatteryUsageStats)
|
.when(mBatteryUsageStats)
|
||||||
.getChargeTimeRemainingMs();
|
.getChargeTimeRemainingMs();
|
||||||
doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
|
doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
|
||||||
|
doReturn(true)
|
||||||
|
.when(mFeatureFactory.powerUsageFeatureProvider)
|
||||||
|
.isBatteryDefend(any(BatteryInfo.class));
|
||||||
Intent intent =
|
Intent intent =
|
||||||
createBatteryIntent(
|
createBatteryIntent(
|
||||||
BatteryManager.BATTERY_PLUGGED_DOCK,
|
BatteryManager.BATTERY_PLUGGED_DOCK,
|
||||||
@@ -709,6 +716,79 @@ public class BatteryInfoTest {
|
|||||||
expectedChargeLabel);
|
expectedChargeLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatteryInfo_chargeOptimizationMode_updateRemainingAndStatusLabel() {
|
||||||
|
prepareTestGetBatteryInfoEnvironment(
|
||||||
|
/* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(),
|
||||||
|
/* chargingStringV2Enabled= */ false);
|
||||||
|
Intent batteryIntent =
|
||||||
|
createIntentForGetBatteryInfoTest(
|
||||||
|
ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65);
|
||||||
|
var expectedRemainingLabel = "Done charging by";
|
||||||
|
var expectedChargeLabel = "65% - " + expectedRemainingLabel;
|
||||||
|
when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode(mContext))
|
||||||
|
.thenReturn(true);
|
||||||
|
when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationRemainingLabel(
|
||||||
|
eq(mContext), anyLong(), anyLong()))
|
||||||
|
.thenReturn(expectedRemainingLabel);
|
||||||
|
when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationChargeLabel(
|
||||||
|
eq(mContext), anyString(), anyLong(), anyLong()))
|
||||||
|
.thenReturn(expectedChargeLabel);
|
||||||
|
var expectedStatusLabel = "Charging";
|
||||||
|
|
||||||
|
assertGetBatteryInfo(
|
||||||
|
batteryIntent,
|
||||||
|
/* currentTimeMillis= */ UNUSED_TIME_MS,
|
||||||
|
expectedStatusLabel,
|
||||||
|
expectedRemainingLabel,
|
||||||
|
expectedChargeLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatteryInfo_notChargeOptimizationModeWithV1_updateRemainingAndStatusLabel() {
|
||||||
|
prepareTestGetBatteryInfoEnvironment(
|
||||||
|
/* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(),
|
||||||
|
/* chargingStringV2Enabled= */ false);
|
||||||
|
Intent batteryIntent =
|
||||||
|
createIntentForGetBatteryInfoTest(
|
||||||
|
ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65);
|
||||||
|
when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode(mContext))
|
||||||
|
.thenReturn(false);
|
||||||
|
var expectedStatusLabel = "Charging";
|
||||||
|
var expectedRemainingLabel = "2 hr, 10 min left until full";
|
||||||
|
var expectedChargeLabel = "65% - " + expectedRemainingLabel;
|
||||||
|
|
||||||
|
assertGetBatteryInfo(
|
||||||
|
batteryIntent,
|
||||||
|
/* currentTimeMillis= */ UNUSED_TIME_MS,
|
||||||
|
expectedStatusLabel,
|
||||||
|
expectedRemainingLabel,
|
||||||
|
expectedChargeLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatteryInfo_notChargeOptimizationModeWithV2_updateRemainingAndStatusLabel() {
|
||||||
|
prepareTestGetBatteryInfoEnvironment(
|
||||||
|
/* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(),
|
||||||
|
/* chargingStringV2Enabled= */ true);
|
||||||
|
Intent batteryIntent =
|
||||||
|
createIntentForGetBatteryInfoTest(
|
||||||
|
ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65);
|
||||||
|
when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode(mContext))
|
||||||
|
.thenReturn(false);
|
||||||
|
var expectedStatusLabel = "Charging";
|
||||||
|
var expectedRemainingLabel = "Fully charged by";
|
||||||
|
var expectedChargeLabel = "65% - " + expectedRemainingLabel;
|
||||||
|
var currentTimeMillis = Instant.parse("2024-04-01T15:00:00Z").toEpochMilli();
|
||||||
|
|
||||||
|
assertGetBatteryInfo(
|
||||||
|
batteryIntent,
|
||||||
|
currentTimeMillis,
|
||||||
|
expectedStatusLabel,
|
||||||
|
expectedRemainingLabel,
|
||||||
|
expectedChargeLabel);
|
||||||
|
}
|
||||||
|
|
||||||
private enum ChargingSpeed {
|
private enum ChargingSpeed {
|
||||||
FAST,
|
FAST,
|
||||||
REGULAR,
|
REGULAR,
|
||||||
|
|||||||
@@ -79,4 +79,20 @@ public class BatterySettingsFeatureProviderImplTest {
|
|||||||
public void getWirelessChargingRemainingLabel_returnNull() {
|
public void getWirelessChargingRemainingLabel_returnNull() {
|
||||||
assertThat(mImpl.getWirelessChargingRemainingLabel(mContext, 1000L, 1000L)).isNull();
|
assertThat(mImpl.getWirelessChargingRemainingLabel(mContext, 1000L, 1000L)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isChargingOptimizationMode_default_returnFalse() {
|
||||||
|
assertThat(mImpl.isChargingOptimizationMode(mContext)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getChargingOptimizationRemainingLabel_default_returnNull() {
|
||||||
|
assertThat(mImpl.getChargingOptimizationRemainingLabel(mContext, 1000L, 1000L)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getChargingOptimizationChargeLabel_default_returnNull() {
|
||||||
|
assertThat(mImpl.getChargingOptimizationChargeLabel(mContext, "70%", 1000L, 1000L))
|
||||||
|
.isNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.mockito.kotlin.doAnswer
|
|||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.spy
|
import org.mockito.kotlin.spy
|
||||||
|
import org.mockito.kotlin.stub
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class CallStateRepositoryTest {
|
class CallStateRepositoryTest {
|
||||||
@@ -86,6 +87,17 @@ class CallStateRepositoryTest {
|
|||||||
.inOrder()
|
.inOrder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isInCallFlow_noActiveSubscription() = runBlocking {
|
||||||
|
mockSubscriptionManager.stub {
|
||||||
|
on { activeSubscriptionIdList } doReturn intArrayOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
|
||||||
|
|
||||||
|
assertThat(isInCall).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isInCallFlow_initial() = runBlocking {
|
fun isInCallFlow_initial() = runBlocking {
|
||||||
val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
|
val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||||
@@ -15,7 +17,6 @@ import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -26,8 +27,9 @@ public final class AppStateAppBatteryUsageBridgeTest {
|
|||||||
private static final int UID_1 = 12345;
|
private static final int UID_1 = 12345;
|
||||||
private static final int UID_2 = 7654321;
|
private static final int UID_2 = 7654321;
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
private ApplicationInfo mApplicationInfo;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private AppOpsManager mAppOpsManager;
|
private AppOpsManager mAppOpsManager;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -36,6 +38,9 @@ public final class AppStateAppBatteryUsageBridgeTest {
|
|||||||
@Before
|
@Before
|
||||||
public void initMocks() {
|
public void initMocks() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
mApplicationInfo = new ApplicationInfo();
|
||||||
|
mApplicationInfo.sourceDir = "test_dir";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -47,7 +52,7 @@ public final class AppStateAppBatteryUsageBridgeTest {
|
|||||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||||
bridge.mAppOpsManager = mAppOpsManager;
|
bridge.mAppOpsManager = mAppOpsManager;
|
||||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||||
AppEntry entry = new AppEntry(mContext, null, 0);
|
AppEntry entry = new AppEntry(mContext, mApplicationInfo, 0);
|
||||||
|
|
||||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_1, UID_1);
|
bridge.updateExtraInfo(entry, TEST_PACKAGE_1, UID_1);
|
||||||
|
|
||||||
@@ -59,14 +64,14 @@ public final class AppStateAppBatteryUsageBridgeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateExtraInfo_updatesUnrestricted() {
|
public void updateExtraInfo_updatesUnrestricted() {
|
||||||
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1, UID_1)).thenReturn(true);
|
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_2, UID_2)).thenReturn(true);
|
||||||
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
||||||
UID_2, TEST_PACKAGE_2)).thenReturn(AppOpsManager.MODE_ALLOWED);
|
UID_2, TEST_PACKAGE_2)).thenReturn(AppOpsManager.MODE_ALLOWED);
|
||||||
AppStateAppBatteryUsageBridge bridge =
|
AppStateAppBatteryUsageBridge bridge =
|
||||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||||
bridge.mAppOpsManager = mAppOpsManager;
|
bridge.mAppOpsManager = mAppOpsManager;
|
||||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||||
AppEntry entry = new AppEntry(mContext, null, 0);
|
AppEntry entry = new AppEntry(mContext, mApplicationInfo, 0);
|
||||||
|
|
||||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_2, UID_2);
|
bridge.updateExtraInfo(entry, TEST_PACKAGE_2, UID_2);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user