Snap for 11811809 from 93fe16fc25 to 24Q3-release
Change-Id: I538b38b49b8f31ea11d61480b4c6777708f44eaa
This commit is contained in:
@@ -240,6 +240,28 @@
|
||||
</intent-filter>
|
||||
</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"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.SubSettings"
|
||||
|
||||
@@ -20,7 +20,7 @@ java_aconfig_library {
|
||||
aconfig_declarations {
|
||||
name: "factory_reset_flags",
|
||||
package: "com.android.settings.factory_reset",
|
||||
container: "system",
|
||||
container: "system_ext",
|
||||
srcs: ["factory_reset/*.aconfig"],
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ java_aconfig_library {
|
||||
aconfig_declarations {
|
||||
name: "media_drm_flags",
|
||||
package: "com.android.settings.media_drm",
|
||||
container: "system",
|
||||
container: "system_ext",
|
||||
srcs: ["media_drm/*.aconfig"],
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ java_aconfig_library {
|
||||
aconfig_declarations {
|
||||
name: "accessibility_flags",
|
||||
package: "com.android.settings.accessibility",
|
||||
container: "system",
|
||||
container: "system_ext",
|
||||
srcs: ["accessibility/*.aconfig"],
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ java_aconfig_library {
|
||||
aconfig_declarations {
|
||||
name: "development_settings_flags",
|
||||
package: "com.android.settings.development",
|
||||
container: "system",
|
||||
container: "system_ext",
|
||||
srcs: [
|
||||
"development/**/*.aconfig",
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package: "com.android.settings.accessibility"
|
||||
container: "system"
|
||||
container: "system_ext"
|
||||
|
||||
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package: "com.android.settings.development"
|
||||
container: "system"
|
||||
container: "system_ext"
|
||||
|
||||
flag {
|
||||
name: "a2dp_offload_codec_extensibility_settings"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package: "com.android.settings.factory_reset"
|
||||
container: "system"
|
||||
container: "system_ext"
|
||||
|
||||
flag {
|
||||
name: "enable_factory_reset_wizard"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package: "com.android.settings.media_drm"
|
||||
container: "system"
|
||||
container: "system_ext"
|
||||
|
||||
flag {
|
||||
name: "force_l3_enabled"
|
||||
namespace: "media_drm"
|
||||
description: "Feature flag of forcing L3"
|
||||
bug: "301669353"
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?android:attr/colorAccent"/>
|
||||
<item android:color="@color/settingslib_materialColorPrimary"/>
|
||||
</selector>
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?androidprv:attr/materialColorPrimaryContainer" />
|
||||
<solid android:color="@color/settingslib_materialColorPrimaryContainer" />
|
||||
<corners android:radius="@dimen/battery_hints_chip_corner_radius" />
|
||||
</shape>
|
||||
@@ -17,6 +17,6 @@
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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" />
|
||||
</shape>
|
||||
@@ -25,7 +25,7 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
android:textColor="@color/settingslib_materialColorOnSurface" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -55,7 +55,7 @@
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/battery_tips_card_action_button"
|
||||
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" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -38,6 +38,6 @@
|
||||
android:paddingHorizontal="8dp"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
|
||||
android:textColor="?androidprv:attr/materialColorOnSurface"/>
|
||||
android:textColor="@color/settingslib_materialColorOnSurface"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
<!-- Power anomaly color for icons, button and text -->
|
||||
<color name="power_anomaly_app_warning_hint_color">#FDD663</color>
|
||||
<color name="power_anomaly_primary_button_text_color">#2E3300</color>
|
||||
|
||||
<!-- UDFPS colors -->
|
||||
<color name="udfps_enroll_icon">#7DA7F1</color>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
|
||||
<item name="colorPrimary">@*android:color/primary_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.-->
|
||||
<item name="android:navigationBarColor">@android:color/black</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||
@@ -29,9 +29,9 @@
|
||||
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
|
||||
|
||||
<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:colorBackground">@*android:color/surface_dark</item>
|
||||
<item name="android:colorBackground">@android:color/system_surface_container_high_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Panel.Material" parent="Theme.Panel" >
|
||||
|
||||
@@ -171,9 +171,8 @@
|
||||
<!-- Icon tint color for battery usage system icon -->
|
||||
<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_primary_button_text_color">#FFFFFF</color>
|
||||
|
||||
<!-- UDFPS colors -->
|
||||
<color name="udfps_enroll_icon">#699FF3</color>
|
||||
|
||||
@@ -115,9 +115,9 @@
|
||||
</style>
|
||||
|
||||
<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:colorBackground">@*android:color/surface_light</item>
|
||||
<item name="android:colorBackground">@android:color/system_surface_container_high_light</item>
|
||||
</style>
|
||||
|
||||
<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.-->
|
||||
<item name="android:navigationBarColor">@android:color/white</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||
<item name="android:colorBackground">@android:color/system_surface_container_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Settings.Home.NoAnimation">
|
||||
|
||||
@@ -15,5 +15,5 @@ menghanli@google.com #{LAST_RESORT_SUGGESTION}
|
||||
cipson@google.com #{LAST_RESORT_SUGGESTION}
|
||||
|
||||
# Partner-team files
|
||||
per-file HapticFeedbackIntensityPreferenceController.java = michaelwr@google.com
|
||||
per-file *Vibration* = michaelwr@google.com
|
||||
per-file HapticFeedbackIntensityPreferenceController.java = file:platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
|
||||
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
|
||||
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(),
|
||||
VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY,
|
||||
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.
|
||||
VibrationPreferenceConfig.playVibrationPreview(
|
||||
mVibrator, VibrationAttributes.USAGE_TOUCH);
|
||||
|
||||
@@ -182,8 +182,10 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
||||
refreshPreferenceController(QuickSettingsShortcutOptionController.class);
|
||||
}
|
||||
|
||||
PreferredShortcuts.updatePreferredShortcutsFromSettings(
|
||||
getContext(), mShortcutTargets);
|
||||
if (getContext() != null) {
|
||||
PreferredShortcuts.updatePreferredShortcutsFromSettings(
|
||||
getContext(), mShortcutTargets);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -388,7 +390,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
||||
private void refreshPreferenceController(
|
||||
Class<? extends AbstractPreferenceController> controllerClass) {
|
||||
AbstractPreferenceController controller = use(controllerClass);
|
||||
if (controller != null) {
|
||||
if (controller != null && getPreferenceScreen() != null) {
|
||||
controller.displayPreference(getPreferenceScreen());
|
||||
if (!TextUtils.isEmpty(controller.getPreferenceKey())) {
|
||||
controller.updateState(findPreference(controller.getPreferenceKey()));
|
||||
|
||||
@@ -87,6 +87,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
implements LifecycleObserver {
|
||||
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
|
||||
* 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";
|
||||
|
||||
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 List<CredentialProviderInfo> mServices;
|
||||
private final Set<String> mEnabledPackageNames;
|
||||
@@ -522,8 +522,13 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
// empty string.
|
||||
String selectedAutofillProvider =
|
||||
DefaultCombinedPicker.getSelectedAutofillProvider(mContext, getUser());
|
||||
if (TextUtils.equals(
|
||||
selectedAutofillProvider, AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER)) {
|
||||
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 = "";
|
||||
}
|
||||
|
||||
@@ -679,6 +684,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
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(
|
||||
@NonNull Context prefContext,
|
||||
@NonNull CharSequence title,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.applications.credentials;
|
||||
|
||||
import static com.android.settings.applications.credentials.CredentialManagerPreferenceController.getCredentialAutofillService;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
@@ -463,9 +465,13 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
||||
private void setProviders(String autofillProvider, List<String> primaryCredManProviders) {
|
||||
if (TextUtils.isEmpty(autofillProvider)) {
|
||||
if (primaryCredManProviders.size() > 0) {
|
||||
autofillProvider =
|
||||
CredentialManagerPreferenceController
|
||||
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
|
||||
if (android.service.autofill.Flags.autofillCredmanDevIntegration()) {
|
||||
autofillProvider = getCredentialAutofillService(getContext(), TAG);
|
||||
} else {
|
||||
autofillProvider =
|
||||
CredentialManagerPreferenceController
|
||||
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -595,6 +595,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
||||
if (Utils.isMonkeyRunning()) {
|
||||
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);
|
||||
final SystemPropPoker poker = SystemPropPoker.getInstance();
|
||||
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;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
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 androidx.annotation.Nullable;
|
||||
@@ -60,7 +65,10 @@ public class Enable16KOemUnlockDialog extends InstrumentedDialogFragment
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.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 */)
|
||||
.create();
|
||||
}
|
||||
@@ -74,4 +82,11 @@ public class Enable16KOemUnlockDialog extends InstrumentedDialogFragment
|
||||
public void onDismiss(@NonNull DialogInterface 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.PowerManager;
|
||||
import android.os.RecoverySystem;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.SystemUpdateManager;
|
||||
import android.os.UpdateEngine;
|
||||
import android.os.UpdateEngineStable;
|
||||
import android.os.UpdateEngineStableCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.service.oemlock.OemLockManager;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.util.Log;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
@@ -59,7 +53,6 @@ import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -80,10 +73,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
private static final String TAG = "Enable16kPages";
|
||||
private static final String REBOOT_REASON = "toggle16k";
|
||||
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_16K_PAGE_SIZE = 1;
|
||||
|
||||
@@ -97,9 +86,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
private static final int OFFSET_TO_FILE_NAME = 30;
|
||||
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 boolean mEnable16k;
|
||||
|
||||
@@ -112,12 +98,12 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
@NonNull Context context, @NonNull DevelopmentSettingsDashboardFragment fragment) {
|
||||
super(context);
|
||||
this.mFragment = fragment;
|
||||
mEnable16k = (PAGE_SIZE == PAGE_SIZE_16KB);
|
||||
mEnable16k = Enable16kUtils.isUsing16kbPages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return SystemProperties.getBoolean(DEV_OPTION_PROPERTY, false);
|
||||
return Enable16kUtils.is16KbToggleAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,12 +115,12 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mEnable16k = (Boolean) newValue;
|
||||
// Prompt user to do oem unlock first
|
||||
if (!isDeviceOEMUnlocked()) {
|
||||
if (!Enable16kUtils.isDeviceOEMUnlocked(mContext)) {
|
||||
Enable16KOemUnlockDialog.show(mFragment);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDataf2fs()) {
|
||||
if (!Enable16kUtils.isDataExt4()) {
|
||||
EnableExt4WarningDialog.show(mFragment, this);
|
||||
return false;
|
||||
}
|
||||
@@ -145,7 +131,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
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 =
|
||||
Settings.Global.getInt(
|
||||
mContext.getContentResolver(),
|
||||
@@ -169,7 +155,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchEnabled() {
|
||||
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(
|
||||
mContext.getContentResolver(), Settings.Global.ENABLE_16K_PAGES, currentStatus);
|
||||
}
|
||||
@@ -432,51 +418,6 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
||||
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
|
||||
private File getOtaFile() throws FileNotFoundException {
|
||||
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) {
|
||||
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) {
|
||||
final CharSequence wirelessChargingLabel =
|
||||
mBatterySettingsFeatureProvider.getWirelessChargingLabel(mContext, info);
|
||||
@@ -85,18 +100,7 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
return wirelessChargingLabel;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (info.statusLabel != null && !info.discharging) {
|
||||
// Charging state
|
||||
if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
|
||||
return info.isFastCharging
|
||||
|
||||
@@ -319,6 +319,12 @@ public class BatteryInfo {
|
||||
info.isFastCharging =
|
||||
BatteryStatus.getChargingSpeed(context, batteryBroadcast)
|
||||
== BatteryStatus.CHARGING_FAST;
|
||||
if (info.isBatteryDefender) {
|
||||
info.isBatteryDefender =
|
||||
FeatureFactory.getFeatureFactory()
|
||||
.getPowerUsageFeatureProvider()
|
||||
.isBatteryDefend(info);
|
||||
}
|
||||
if (!info.mCharging) {
|
||||
updateBatteryInfoDischarging(context, shortString, estimate, info);
|
||||
} else {
|
||||
@@ -388,9 +394,10 @@ public class BatteryInfo {
|
||||
&& status != BatteryManager.BATTERY_STATUS_FULL
|
||||
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|
||||
|| dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
|
||||
final BatterySettingsFeatureProvider featureProvider =
|
||||
FeatureFactory.getFeatureFactory().getBatterySettingsFeatureProvider();
|
||||
// Battery is charging to full
|
||||
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
|
||||
|
||||
int resId = getChargingDurationResId(info.isFastCharging);
|
||||
info.remainingLabel =
|
||||
chargeTimeMs <= 0
|
||||
@@ -400,7 +407,8 @@ public class BatteryInfo {
|
||||
chargeTimeMs,
|
||||
info.isFastCharging,
|
||||
info.pluggedStatus,
|
||||
currentTimeMs);
|
||||
currentTimeMs,
|
||||
featureProvider);
|
||||
|
||||
info.chargeLabel =
|
||||
chargeTimeMs <= 0
|
||||
@@ -411,7 +419,8 @@ public class BatteryInfo {
|
||||
info.batteryPercentString,
|
||||
chargeTimeMs,
|
||||
info.isFastCharging,
|
||||
currentTimeMs);
|
||||
currentTimeMs,
|
||||
featureProvider);
|
||||
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
|
||||
// Dock defender will be triggered in the future, charging will be optimized.
|
||||
info.chargeLabel =
|
||||
@@ -436,10 +445,17 @@ public class BatteryInfo {
|
||||
long chargeRemainingTimeMs,
|
||||
boolean isFastCharging,
|
||||
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) {
|
||||
BatterySettingsFeatureProvider featureProvider =
|
||||
FeatureFactory.getFeatureFactory().getBatterySettingsFeatureProvider();
|
||||
final CharSequence wirelessChargingRemainingLabel =
|
||||
featureProvider.getWirelessChargingRemainingLabel(
|
||||
context, chargeRemainingTimeMs, currentTimeMs);
|
||||
@@ -472,7 +488,16 @@ public class BatteryInfo {
|
||||
String batteryPercentString,
|
||||
long chargeTimeMs,
|
||||
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()) {
|
||||
var timeString =
|
||||
PowerUtil.getTargetTimeShortString(context, chargeTimeMs, currentTimeMs);
|
||||
|
||||
@@ -53,4 +53,20 @@ public interface BatterySettingsFeatureProvider {
|
||||
@Nullable
|
||||
CharSequence getWirelessChargingRemainingLabel(
|
||||
@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) {
|
||||
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)
|
||||
|
||||
if (Flags.isDualSimOnboardingEnabled()) {
|
||||
context?.startSpaActivity(NetworkCellularGroupProvider.name);
|
||||
context?.startSpaActivity(NetworkCellularGroupProvider.fileName)
|
||||
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.VisibleForTesting;
|
||||
|
||||
import com.android.settings.network.helper.SubscriptionAnnotation;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -103,15 +102,6 @@ public class SelectableSubscriptions implements Callable<List<SubscriptionAnnota
|
||||
TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
|
||||
|
||||
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
|
||||
Future<AtomicIntegerArray> activeSimSlotIndex =
|
||||
ThreadUtils.postOnBackgroundThread(
|
||||
@@ -120,16 +110,13 @@ public class SelectableSubscriptions implements Callable<List<SubscriptionAnnota
|
||||
List<SubscriptionInfo> subInfoList = mSubscriptions.get();
|
||||
|
||||
// wait for result from background thread
|
||||
List<Integer> eSimCardIdList = atomicToList(eSimCardId.get());
|
||||
List<Integer> simSlotIndexList = atomicToList(simSlotIndex.get());
|
||||
List<Integer> activeSimSlotIndexList = atomicToList(activeSimSlotIndex.get());
|
||||
|
||||
// build a list of SubscriptionAnnotation
|
||||
return IntStream.range(0, subInfoList.size())
|
||||
.mapToObj(subInfoIndex ->
|
||||
new SubscriptionAnnotation.Builder(subInfoList, subInfoIndex))
|
||||
.map(annoBdr -> annoBdr.build(mContext,
|
||||
eSimCardIdList, simSlotIndexList, activeSimSlotIndexList))
|
||||
.map(annoBdr -> annoBdr.build(mContext, activeSimSlotIndexList))
|
||||
.filter(mFilter)
|
||||
.collect(Collectors.collectingAndThen(Collectors.toList(), mFinisher));
|
||||
} catch (Exception exception) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.settings.network.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
@@ -35,14 +34,11 @@ public class SubscriptionAnnotation {
|
||||
private static final String TAG = "SubscriptionAnnotation";
|
||||
|
||||
private SubscriptionInfo mSubInfo;
|
||||
private int mOrderWithinList;
|
||||
private int mType = TYPE_UNKNOWN;
|
||||
private boolean mIsExisted;
|
||||
private boolean mIsActive;
|
||||
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_PSIM = 0x1;
|
||||
public static final int TYPE_ESIM = 0x2;
|
||||
@@ -52,8 +48,8 @@ public class SubscriptionAnnotation {
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private List<SubscriptionInfo> mSubInfoList;
|
||||
private int mIndexWithinList;
|
||||
private final List<SubscriptionInfo> mSubInfoList;
|
||||
private final int mIndexWithinList;
|
||||
|
||||
/**
|
||||
* Constructor of builder
|
||||
@@ -65,10 +61,9 @@ public class SubscriptionAnnotation {
|
||||
mIndexWithinList = indexWithinList;
|
||||
}
|
||||
|
||||
public SubscriptionAnnotation build(Context context, List<Integer> eSimCardId,
|
||||
List<Integer> simSlotIndex, List<Integer> activeSimSlotIndex) {
|
||||
public SubscriptionAnnotation build(Context context, List<Integer> activeSimSlotIndex) {
|
||||
return new SubscriptionAnnotation(mSubInfoList, mIndexWithinList, context,
|
||||
eSimCardId, simSlotIndex, activeSimSlotIndex);
|
||||
activeSimSlotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +73,7 @@ public class SubscriptionAnnotation {
|
||||
@Keep
|
||||
@VisibleForTesting
|
||||
protected SubscriptionAnnotation(List<SubscriptionInfo> subInfoList, int subInfoIndex,
|
||||
Context context, List<Integer> eSimCardId,
|
||||
List<Integer> simSlotIndex, List<Integer> activeSimSlotIndexList) {
|
||||
Context context, List<Integer> activeSimSlotIndexList) {
|
||||
if ((subInfoIndex < 0) || (subInfoIndex >= subInfoList.size())) {
|
||||
return;
|
||||
}
|
||||
@@ -88,7 +82,6 @@ public class SubscriptionAnnotation {
|
||||
return;
|
||||
}
|
||||
|
||||
mOrderWithinList = subInfoIndex;
|
||||
mType = mSubInfo.isEmbedded() ? TYPE_ESIM : TYPE_PSIM;
|
||||
mIsExisted = true;
|
||||
if (mType == TYPE_ESIM) {
|
||||
@@ -104,12 +97,6 @@ public class SubscriptionAnnotation {
|
||||
mIsAllowToDisplay = isDisplayAllowed(context);
|
||||
}
|
||||
|
||||
// the index provided during construction of Builder
|
||||
@Keep
|
||||
public int getOrderingInList() {
|
||||
return mOrderWithinList;
|
||||
}
|
||||
|
||||
// type of subscription
|
||||
@Keep
|
||||
public int getType() {
|
||||
@@ -141,12 +128,6 @@ public class SubscriptionAnnotation {
|
||||
mSubInfo.getSubscriptionId();
|
||||
}
|
||||
|
||||
// the grouping UUID
|
||||
@Keep
|
||||
public ParcelUuid getGroupUuid() {
|
||||
return (mSubInfo == null) ? null : mSubInfo.getGroupUuid();
|
||||
}
|
||||
|
||||
// the SubscriptionInfo
|
||||
@Keep
|
||||
public SubscriptionInfo getSubInfo() {
|
||||
|
||||
@@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@@ -50,8 +51,12 @@ class CallStateRepository(private val context: Context) {
|
||||
fun isInCallFlow(): Flow<Boolean> = context.subscriptionsChangedFlow()
|
||||
.flatMapLatest {
|
||||
val subIds = subscriptionManager.activeSubscriptionIdList
|
||||
combine(subIds.map(::callStateFlow)) { states ->
|
||||
states.any { it != TelephonyManager.CALL_STATE_IDLE }
|
||||
if (subIds.isEmpty()) {
|
||||
flowOf(false)
|
||||
} else {
|
||||
combine(subIds.map(::callStateFlow)) { states ->
|
||||
states.any { it != TelephonyManager.CALL_STATE_IDLE }
|
||||
}
|
||||
}
|
||||
}
|
||||
.conflate()
|
||||
|
||||
@@ -50,7 +50,14 @@ public class PanelFeatureProviderImpl implements PanelFeatureProvider {
|
||||
context.sendBroadcast(intent);
|
||||
return null;
|
||||
case Settings.Panel.ACTION_NFC:
|
||||
return NfcPanel.create(context);
|
||||
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);
|
||||
}
|
||||
case Settings.Panel.ACTION_WIFI:
|
||||
if (Flags.slicesRetirement()) {
|
||||
Intent wifiIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
|
||||
|
||||
@@ -31,10 +31,10 @@ import android.telephony.UiccCardInfo;
|
||||
import android.telephony.UiccSlotInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.network.SubscriptionUtil;
|
||||
import com.android.settings.network.UiccSlotUtil;
|
||||
import com.android.settings.network.UiccSlotsException;
|
||||
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
|
||||
import com.android.settings.sim.ChooseSimActivity;
|
||||
import com.android.settings.sim.DsdsDialogActivity;
|
||||
import com.android.settings.sim.SimActivationNotifier;
|
||||
@@ -86,11 +86,6 @@ public class SimSlotChangeHandler {
|
||||
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();
|
||||
if (removableSlotInfo == null) {
|
||||
Log.e(TAG, "Unable to find the removable slot. Do nothing.");
|
||||
@@ -112,12 +107,25 @@ public class SimSlotChangeHandler {
|
||||
// Sets the current removable slot state.
|
||||
setRemovableSimSlotState(mContext, currentRemovableSlotState);
|
||||
|
||||
if (mTelMgr.getActiveModemCount() > 1 && isMultipleEnabledProfilesSupported()) {
|
||||
if(!isRemovableSimInserted) {
|
||||
Log.i(TAG, "Removable Sim is not inserted in DSDS mode and MEP. Do nothing.");
|
||||
if (mTelMgr.getActiveModemCount() > 1) {
|
||||
if (!Flags.isDualSimOnboardingEnabled() && !isMultipleEnabledProfilesSupported()) {
|
||||
Log.d(TAG, "The device is already in DSDS mode and no MEP. Do nothing.");
|
||||
return;
|
||||
}
|
||||
handleRemovableSimInsertUnderDsdsMep(removableSlotInfo);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "the device is already in DSDS mode and have the DDS. Do nothing.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -164,8 +172,8 @@ public class SimSlotChangeHandler {
|
||||
Log.i(
|
||||
TAG,
|
||||
"Both removable SIM and eSIM are present. DSDS condition doesn't"
|
||||
+ " satisfied. User inserted pSIM during SUW. Show choose SIM"
|
||||
+ " screen.");
|
||||
+ " satisfied. User inserted pSIM during SUW. Show choose SIM"
|
||||
+ " screen.");
|
||||
startChooseSimActivity(true);
|
||||
}
|
||||
} else if (removableSlotAction == LAST_USER_ACTION_IN_SUW_REMOVE) {
|
||||
@@ -232,8 +240,8 @@ public class SimSlotChangeHandler {
|
||||
if (groupedEmbeddedSubscriptions.size() == 0 || !removableSlotInfo.getPorts().stream()
|
||||
.findFirst().get().isActive()) {
|
||||
Log.i(TAG, "eSIM slot is active or no subscriptions exist. Do nothing."
|
||||
+ " The removableSlotInfo: " + removableSlotInfo
|
||||
+ ", groupedEmbeddedSubscriptions: " + groupedEmbeddedSubscriptions);
|
||||
+ " The removableSlotInfo: " + removableSlotInfo
|
||||
+ ", groupedEmbeddedSubscriptions: " + groupedEmbeddedSubscriptions);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,6 +259,17 @@ public class SimSlotChangeHandler {
|
||||
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) {
|
||||
Log.i(TAG, "Handle Removable SIM inserted under DSDS+Mep.");
|
||||
|
||||
@@ -309,7 +328,7 @@ public class SimSlotChangeHandler {
|
||||
try {
|
||||
// DEVICE_PROVISIONED is 0 if still in setup wizard. 1 if setup completed.
|
||||
return Settings.Global.getInt(
|
||||
context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED)
|
||||
context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED)
|
||||
== 1;
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
Log.e(TAG, "Cannot get DEVICE_PROVISIONED from the device.", e);
|
||||
|
||||
@@ -118,7 +118,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
|
||||
ApnEditPageProvider,
|
||||
SimOnboardingPageProvider,
|
||||
BatteryOptimizationModeAppListPageProvider,
|
||||
NetworkCellularGroupProvider,
|
||||
NetworkCellularGroupProvider(),
|
||||
WifiPrivacyPageProvider,
|
||||
)
|
||||
|
||||
|
||||
@@ -94,9 +94,7 @@ class InstallUnknownAppsListModel(private val context: Context) :
|
||||
private fun isChangeable(
|
||||
record: InstallUnknownAppsRecord,
|
||||
potentialPackageNames: Set<String>,
|
||||
) =
|
||||
record.appOpsController.getMode() != MODE_DEFAULT ||
|
||||
record.app.packageName in potentialPackageNames
|
||||
) = record.app.packageName in potentialPackageNames
|
||||
|
||||
private fun getPotentialPackageNames(userId: Int): Set<String> =
|
||||
AppGlobals.getPackageManager()
|
||||
|
||||
@@ -75,8 +75,8 @@ import kotlinx.coroutines.withContext
|
||||
/**
|
||||
* Showing the sim onboarding which is the process flow of sim switching on.
|
||||
*/
|
||||
object NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
override val name = "NetworkCellularGroupProvider"
|
||||
open class NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
override val name = fileName
|
||||
|
||||
private val owner = createSettingsPage()
|
||||
|
||||
@@ -85,7 +85,7 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
var defaultDataSubId: 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 {
|
||||
// never using
|
||||
Preference(object : PreferenceModel {
|
||||
@@ -123,13 +123,26 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
nonDdsRemember.intValue = nonDds
|
||||
}
|
||||
|
||||
PageImpl(
|
||||
subscriptionViewModel.selectableSubscriptionInfoListFlow,
|
||||
callsSelectedId,
|
||||
textsSelectedId,
|
||||
mobileDataSelectedId,
|
||||
nonDdsRemember
|
||||
)
|
||||
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,
|
||||
callsSelectedId,
|
||||
textsSelectedId,
|
||||
mobileDataSelectedId,
|
||||
)
|
||||
|
||||
OtherSection()
|
||||
}
|
||||
}
|
||||
|
||||
private fun allOfFlows(context: Context,
|
||||
@@ -139,7 +152,7 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
context.defaultVoiceSubscriptionFlow(),
|
||||
context.defaultSmsSubscriptionFlow(),
|
||||
context.defaultDefaultDataSubscriptionFlow(),
|
||||
NetworkCellularGroupProvider::refreshUiStates,
|
||||
this::refreshUiStates,
|
||||
).flowOn(Dispatchers.Default)
|
||||
|
||||
private fun refreshUiStates(
|
||||
@@ -164,32 +177,12 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
|
||||
|
||||
Log.d(name, "defaultDataSubId: $defaultDataSubId, nonDds: $nonDds")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PageImpl(
|
||||
selectableSubscriptionInfoListFlow: StateFlow<List<SubscriptionInfo>>,
|
||||
defaultVoiceSubId: MutableIntState,
|
||||
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,
|
||||
)
|
||||
@Composable
|
||||
open fun OtherSection(){
|
||||
// Do nothing
|
||||
}
|
||||
companion object {
|
||||
const val fileName = "NetworkCellularGroupProvider"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,9 +410,9 @@ suspend fun setMobileData(
|
||||
enabled: Boolean,
|
||||
): Unit =
|
||||
withContext(Dispatchers.Default) {
|
||||
Log.d(NetworkCellularGroupProvider.name, "setMobileData: $enabled")
|
||||
Log.d(NetworkCellularGroupProvider.fileName, "setMobileData: $enabled")
|
||||
if (enabled) {
|
||||
Log.d(NetworkCellularGroupProvider.name, "setDefaultData: [$subId]")
|
||||
Log.d(NetworkCellularGroupProvider.fileName, "setDefaultData: [$subId]")
|
||||
subscriptionManager?.setDefaultDataSubId(subId)
|
||||
}
|
||||
TelephonyRepository(context)
|
||||
|
||||
@@ -75,6 +75,7 @@ public class GuestTelephonyPreferenceController extends TogglePreferenceControll
|
||||
super.updateState(preference);
|
||||
mUserCaps.updateAddUserCapabilities(mContext);
|
||||
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
|
||||
removePreference(KEY_ENABLE_TELEPHONY);
|
||||
}
|
||||
if (mUserInfo.isMain()) {
|
||||
if (mUserInfo.isMain() || UserManager.isHeadlessSystemUserMode()) {
|
||||
removePreference(KEY_ENABLE_TELEPHONY);
|
||||
}
|
||||
if (mUserInfo.isRestricted()) {
|
||||
|
||||
@@ -62,13 +62,13 @@ public class Enable16kPagesPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
public void onSystemPropertyDisabled_shouldDisablePreference() {
|
||||
SystemProperties.set(Enable16kPagesPreferenceController.DEV_OPTION_PROPERTY, "false");
|
||||
SystemProperties.set(Enable16kUtils.DEV_OPTION_PROPERTY, "false");
|
||||
assertThat(mController.isAvailable()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSystemPropertyEnabled_shouldEnablePreference() {
|
||||
SystemProperties.set(Enable16kPagesPreferenceController.DEV_OPTION_PROPERTY, "true");
|
||||
SystemProperties.set(Enable16kUtils.DEV_OPTION_PROPERTY, "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.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
@@ -307,6 +308,9 @@ public class BatteryInfoTest {
|
||||
@Test
|
||||
public void getBatteryInfo_chargingWithDefender_updateChargeLabel() {
|
||||
doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs();
|
||||
doReturn(true)
|
||||
.when(mFeatureFactory.powerUsageFeatureProvider)
|
||||
.isBatteryDefend(any(BatteryInfo.class));
|
||||
mChargingBatteryBroadcast.putExtra(
|
||||
BatteryManager.EXTRA_CHARGING_STATUS,
|
||||
BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
|
||||
@@ -363,6 +367,9 @@ public class BatteryInfoTest {
|
||||
.when(mBatteryUsageStats)
|
||||
.getChargeTimeRemainingMs();
|
||||
doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
|
||||
doReturn(true)
|
||||
.when(mFeatureFactory.powerUsageFeatureProvider)
|
||||
.isBatteryDefend(any(BatteryInfo.class));
|
||||
Intent intent =
|
||||
createBatteryIntent(
|
||||
BatteryManager.BATTERY_PLUGGED_DOCK,
|
||||
@@ -709,6 +716,79 @@ public class BatteryInfoTest {
|
||||
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 {
|
||||
FAST,
|
||||
REGULAR,
|
||||
|
||||
@@ -79,4 +79,20 @@ public class BatterySettingsFeatureProviderImplTest {
|
||||
public void getWirelessChargingRemainingLabel_returnNull() {
|
||||
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.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.stub
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CallStateRepositoryTest {
|
||||
@@ -86,6 +87,17 @@ class CallStateRepositoryTest {
|
||||
.inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isInCallFlow_noActiveSubscription() = runBlocking {
|
||||
mockSubscriptionManager.stub {
|
||||
on { activeSubscriptionIdList } doReturn intArrayOf()
|
||||
}
|
||||
|
||||
val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
|
||||
|
||||
assertThat(isInCall).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isInCallFlow_initial() = runBlocking {
|
||||
val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
|
||||
|
||||
@@ -6,7 +6,9 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
@@ -15,64 +17,67 @@ import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class AppStateAppBatteryUsageBridgeTest {
|
||||
private static final String TEST_PACKAGE_1 = "com.example.test.pkg1";
|
||||
private static final String TEST_PACKAGE_2 = "com.example.test.pkg2";
|
||||
private static final int UID_1 = 12345;
|
||||
private static final int UID_2 = 7654321;
|
||||
private static final String TEST_PACKAGE_1 = "com.example.test.pkg1";
|
||||
private static final String TEST_PACKAGE_2 = "com.example.test.pkg2";
|
||||
private static final int UID_1 = 12345;
|
||||
private static final int UID_2 = 7654321;
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private PowerAllowlistBackend mPowerAllowlistBackend;
|
||||
private Context mContext;
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
@Mock
|
||||
private AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private PowerAllowlistBackend mPowerAllowlistBackend;
|
||||
|
||||
@Test
|
||||
public void updateExtraInfo_updatesRestricted() {
|
||||
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1, UID_1)).thenReturn(false);
|
||||
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
||||
UID_1, TEST_PACKAGE_1)).thenReturn(AppOpsManager.MODE_IGNORED);
|
||||
AppStateAppBatteryUsageBridge bridge =
|
||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||
bridge.mAppOpsManager = mAppOpsManager;
|
||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||
AppEntry entry = new AppEntry(mContext, null, 0);
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
mApplicationInfo = new ApplicationInfo();
|
||||
mApplicationInfo.sourceDir = "test_dir";
|
||||
}
|
||||
|
||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_1, UID_1);
|
||||
@Test
|
||||
public void updateExtraInfo_updatesRestricted() {
|
||||
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1, UID_1)).thenReturn(false);
|
||||
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
||||
UID_1, TEST_PACKAGE_1)).thenReturn(AppOpsManager.MODE_IGNORED);
|
||||
AppStateAppBatteryUsageBridge bridge =
|
||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||
bridge.mAppOpsManager = mAppOpsManager;
|
||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||
AppEntry entry = new AppEntry(mContext, mApplicationInfo, 0);
|
||||
|
||||
assertThat(entry.extraInfo.getClass())
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
|
||||
assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.MODE_RESTRICTED);
|
||||
}
|
||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_1, UID_1);
|
||||
|
||||
@Test
|
||||
public void updateExtraInfo_updatesUnrestricted() {
|
||||
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1, UID_1)).thenReturn(true);
|
||||
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
||||
UID_2, TEST_PACKAGE_2)).thenReturn(AppOpsManager.MODE_ALLOWED);
|
||||
AppStateAppBatteryUsageBridge bridge =
|
||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||
bridge.mAppOpsManager = mAppOpsManager;
|
||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||
AppEntry entry = new AppEntry(mContext, null, 0);
|
||||
assertThat(entry.extraInfo.getClass())
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
|
||||
assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.MODE_RESTRICTED);
|
||||
}
|
||||
|
||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_2, UID_2);
|
||||
@Test
|
||||
public void updateExtraInfo_updatesUnrestricted() {
|
||||
when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_2, UID_2)).thenReturn(true);
|
||||
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
|
||||
UID_2, TEST_PACKAGE_2)).thenReturn(AppOpsManager.MODE_ALLOWED);
|
||||
AppStateAppBatteryUsageBridge bridge =
|
||||
new AppStateAppBatteryUsageBridge(mContext, null, null);
|
||||
bridge.mAppOpsManager = mAppOpsManager;
|
||||
bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
|
||||
AppEntry entry = new AppEntry(mContext, mApplicationInfo, 0);
|
||||
|
||||
assertThat(entry.extraInfo.getClass())
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
|
||||
assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.MODE_UNRESTRICTED);
|
||||
}
|
||||
bridge.updateExtraInfo(entry, TEST_PACKAGE_2, UID_2);
|
||||
|
||||
assertThat(entry.extraInfo.getClass())
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
|
||||
assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
|
||||
.isEqualTo(AppStateAppBatteryUsageBridge.MODE_UNRESTRICTED);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user