diff --git a/Android.bp b/Android.bp
index d2b8fc75bdc..71e0542f793 100644
--- a/Android.bp
+++ b/Android.bp
@@ -83,6 +83,7 @@ android_library {
"net-utils-framework-common",
"app-usage-event-protos-lite",
"battery-event-protos-lite",
+ "power-anomaly-event-protos-lite",
"settings-contextual-card-protos-lite",
"settings-log-bridge-protos-lite",
"settings-telephony-protos-lite",
diff --git a/res/values/config.xml b/res/values/config.xml
index 432b1cad01b..687fa1596bc 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -611,23 +611,26 @@
- 3
-
-
- @string/user_aspect_ratio_app_default
+ - @string/user_aspect_ratio_fullscreen
- @string/user_aspect_ratio_half_screen
+ - @string/user_aspect_ratio_device_size
- @string/user_aspect_ratio_16_9
- @string/user_aspect_ratio_4_3
- @string/user_aspect_ratio_3_2
-
- 0
+ - 6
- 1
+ - 2
- 4
- 3
- 5
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e7b5d138683..ba5f72db554 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12081,25 +12081,32 @@
other {Apps installed more than # months ago}
}
-
-
- Screen size
-
- Choose an aspect ratio for apps if they haven’t been optimized for your %1$s
+
+
+ Aspect ratio
+
+ Choose an aspect ratio to view this app if it hasn\'t been designed to fit your %1$s
Suggested apps
Apps you have overridden
App default
-
- Half-screen
+
+ Full screen
+
+ Half screen
+
+ Device aspect ratio
16:9
3:2
4:3
+
+ The app will restart when you change aspect ratio. You may lose unsaved changes.
+
Fingerprint sensor
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 386a07bde55..73bcbc9b9e7 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -81,7 +81,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java b/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java
index 6ec2528da4a..ff68fb015f2 100644
--- a/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java
@@ -43,6 +43,6 @@ public class UserAspectRatioAppsPreferenceController extends BasePreferenceContr
@Override
public CharSequence getSummary() {
- return mContext.getResources().getString(R.string.screen_size_summary, Build.MODEL);
+ return mContext.getResources().getString(R.string.aspect_ratio_summary, Build.MODEL);
}
}
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
new file mode 100644
index 00000000000..f8406f90a50
--- /dev/null
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appcompat;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.applications.AppInfoWithHeader;
+import com.android.settingslib.widget.ActionButtonsPreference;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * App specific activity to show aspect ratio overrides
+ */
+public class UserAspectRatioDetails extends AppInfoWithHeader implements
+ SelectorWithWidgetPreference.OnClickListener {
+ private static final String TAG = UserAspectRatioDetails.class.getSimpleName();
+
+ private static final String KEY_HEADER_BUTTONS = "header_view";
+ private static final String KEY_PREF_FULLSCREEN = "fullscreen_pref";
+ private static final String KEY_PREF_HALF_SCREEN = "half_screen_pref";
+ private static final String KEY_PREF_DISPLAY_SIZE = "display_size_pref";
+ private static final String KEY_PREF_16_9 = "16_9_pref";
+ private static final String KEY_PREF_4_3 = "4_3_pref";
+ @VisibleForTesting
+ static final String KEY_PREF_DEFAULT = "app_default_pref";
+ @VisibleForTesting
+ static final String KEY_PREF_3_2 = "3_2_pref";
+
+ private final List mAspectRatioPreferences = new ArrayList<>();
+
+ @NonNull private UserAspectRatioManager mUserAspectRatioManager;
+ @NonNull private String mSelectedKey = KEY_PREF_DEFAULT;
+
+ @Override
+ public void onCreate(@NonNull Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mUserAspectRatioManager = new UserAspectRatioManager(getContext());
+ initPreferences();
+ try {
+ final int userAspectRatio = mUserAspectRatioManager
+ .getUserMinAspectRatioValue(mPackageName, mUserId);
+ mSelectedKey = getSelectedKey(userAspectRatio);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get user min aspect ratio");
+ }
+ refreshUi();
+ }
+
+ @Override
+ public void onRadioButtonClicked(@NonNull SelectorWithWidgetPreference selected) {
+ final String selectedKey = selected.getKey();
+ if (mSelectedKey.equals(selectedKey)) {
+ return;
+ }
+ final int userAspectRatio = getSelectedUserMinAspectRatio(selectedKey);
+ try {
+ getAspectRatioManager().setUserMinAspectRatio(mPackageName, mUserId, userAspectRatio);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to set user min aspect ratio");
+ return;
+ }
+ // Only update to selected aspect ratio if nothing goes wrong
+ mSelectedKey = selectedKey;
+ updateAllPreferences(mSelectedKey);
+ Log.d(TAG, "Killing application process " + mPackageName);
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ am.stopAppForUser(mPackageName, mUserId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to stop application " + mPackageName);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO(b/292566895): add metrics for logging
+ return 0;
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
+ return false;
+ }
+ updateAllPreferences(mSelectedKey);
+ return true;
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ return null;
+ }
+
+ private void launchApplication() {
+ Intent launchIntent = mPm.getLaunchIntentForPackage(mPackageName)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
+ if (launchIntent != null) {
+ getContext().startActivityAsUser(launchIntent, new UserHandle(mUserId));
+ }
+ }
+
+ @PackageManager.UserMinAspectRatio
+ private int getSelectedUserMinAspectRatio(@NonNull String selectedKey) {
+ switch (selectedKey) {
+ case KEY_PREF_FULLSCREEN:
+ return USER_MIN_ASPECT_RATIO_FULLSCREEN;
+ case KEY_PREF_HALF_SCREEN:
+ return USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
+ case KEY_PREF_DISPLAY_SIZE:
+ return USER_MIN_ASPECT_RATIO_DISPLAY_SIZE;
+ case KEY_PREF_3_2:
+ return USER_MIN_ASPECT_RATIO_3_2;
+ case KEY_PREF_4_3:
+ return USER_MIN_ASPECT_RATIO_4_3;
+ case KEY_PREF_16_9:
+ return USER_MIN_ASPECT_RATIO_16_9;
+ default:
+ return USER_MIN_ASPECT_RATIO_UNSET;
+ }
+ }
+
+ @NonNull
+ private String getSelectedKey(@PackageManager.UserMinAspectRatio int userMinAspectRatio) {
+ switch (userMinAspectRatio) {
+ case USER_MIN_ASPECT_RATIO_FULLSCREEN:
+ return KEY_PREF_FULLSCREEN;
+ case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
+ return KEY_PREF_HALF_SCREEN;
+ case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE:
+ return KEY_PREF_DISPLAY_SIZE;
+ case USER_MIN_ASPECT_RATIO_3_2:
+ return KEY_PREF_3_2;
+ case USER_MIN_ASPECT_RATIO_4_3:
+ return KEY_PREF_4_3;
+ case USER_MIN_ASPECT_RATIO_16_9:
+ return KEY_PREF_16_9;
+ default:
+ return KEY_PREF_DEFAULT;
+ }
+ }
+
+ private void initPreferences() {
+ addPreferencesFromResource(R.xml.user_aspect_ratio_details);
+
+ ((ActionButtonsPreference) findPreference(KEY_HEADER_BUTTONS))
+ .setButton1Text(R.string.launch_instant_app)
+ .setButton1Icon(R.drawable.ic_settings_open)
+ .setButton1OnClickListener(v -> launchApplication());
+
+ addPreference(KEY_PREF_DEFAULT, USER_MIN_ASPECT_RATIO_UNSET);
+ addPreference(KEY_PREF_FULLSCREEN, USER_MIN_ASPECT_RATIO_FULLSCREEN);
+ addPreference(KEY_PREF_DISPLAY_SIZE, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE);
+ addPreference(KEY_PREF_HALF_SCREEN, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN);
+ addPreference(KEY_PREF_16_9, USER_MIN_ASPECT_RATIO_16_9);
+ addPreference(KEY_PREF_4_3, USER_MIN_ASPECT_RATIO_4_3);
+ addPreference(KEY_PREF_3_2, USER_MIN_ASPECT_RATIO_3_2);
+ }
+
+ private void addPreference(@NonNull String key,
+ @PackageManager.UserMinAspectRatio int aspectRatio) {
+ final SelectorWithWidgetPreference pref = findPreference(key);
+ if (pref == null) {
+ return;
+ }
+ if (!mUserAspectRatioManager.containsAspectRatioOption(aspectRatio)) {
+ pref.setVisible(false);
+ return;
+ }
+ pref.setTitle(mUserAspectRatioManager.getUserMinAspectRatioEntry(aspectRatio));
+ pref.setOnClickListener(this);
+ mAspectRatioPreferences.add(pref);
+ }
+
+ private void updateAllPreferences(@NonNull String selectedKey) {
+ for (SelectorWithWidgetPreference pref : mAspectRatioPreferences) {
+ pref.setChecked(selectedKey.equals(pref.getKey()));
+ }
+ }
+
+ @VisibleForTesting
+ UserAspectRatioManager getAspectRatioManager() {
+ return mUserAspectRatioManager;
+ }
+}
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
index 35bd7a93a1d..c132fd0f602 100644
--- a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
@@ -28,6 +28,7 @@ import android.provider.DeviceConfig;
import android.util.ArrayMap;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.settings.R;
@@ -49,6 +50,9 @@ public class UserAspectRatioManager {
@VisibleForTesting
static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
"enable_app_compat_user_aspect_ratio_settings";
+ static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN =
+ "enable_app_compat_user_aspect_ratio_fullscreen";
+ private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true;
private final Context mContext;
private final IPackageManager mIPm;
@@ -70,7 +74,8 @@ public class UserAspectRatioManager {
public static boolean isFeatureEnabled(Context context) {
final boolean isBuildTimeFlagEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled);
- return isBuildTimeFlagEnabled && getValueFromDeviceConfig();
+ return getValueFromDeviceConfig(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS,
+ DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS) && isBuildTimeFlagEnabled;
}
/**
@@ -79,7 +84,9 @@ public class UserAspectRatioManager {
@PackageManager.UserMinAspectRatio
public int getUserMinAspectRatioValue(@NonNull String packageName, int uid)
throws RemoteException {
- return mIPm.getUserMinAspectRatio(packageName, uid);
+ final int aspectRatio = mIPm.getUserMinAspectRatio(packageName, uid);
+ return containsAspectRatioOption(aspectRatio)
+ ? aspectRatio : PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
}
/**
@@ -87,8 +94,41 @@ public class UserAspectRatioManager {
*/
@NonNull
public String getUserMinAspectRatioEntry(@PackageManager.UserMinAspectRatio int aspectRatio) {
- return mUserAspectRatioMap.getOrDefault(
- aspectRatio, mContext.getString(R.string.user_aspect_ratio_app_default));
+ if (!containsAspectRatioOption(aspectRatio)) {
+ return mUserAspectRatioMap.get(PackageManager.USER_MIN_ASPECT_RATIO_UNSET);
+ }
+ return mUserAspectRatioMap.get(aspectRatio);
+ }
+
+ /**
+ * @return corresponding aspect ratio string for package name and user
+ */
+ @NonNull
+ public String getUserMinAspectRatioEntry(@NonNull String packageName, int uid)
+ throws RemoteException {
+ final int aspectRatio = getUserMinAspectRatioValue(packageName, uid);
+ return getUserMinAspectRatioEntry(aspectRatio);
+ }
+
+ /**
+ * Whether user aspect ratio option is specified in
+ * {@link R.array.config_userAspectRatioOverrideValues}
+ * and is enabled by device config
+ */
+ public boolean containsAspectRatioOption(@PackageManager.UserMinAspectRatio int option) {
+ if (option == PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN
+ && !isFullscreenOptionEnabled()) {
+ return false;
+ }
+ return mUserAspectRatioMap.containsKey(option);
+ }
+
+ /**
+ * Sets user-specified {@link PackageManager.UserMinAspectRatio} override for an app
+ */
+ public void setUserMinAspectRatio(@NonNull String packageName, int uid,
+ @PackageManager.UserMinAspectRatio int aspectRatio) throws RemoteException {
+ mIPm.setUserMinAspectRatio(packageName, uid, aspectRatio);
}
/**
@@ -101,11 +141,20 @@ public class UserAspectRatioManager {
return hasLauncherEntry;
}
- private static boolean getValueFromDeviceConfig() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS,
- DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS);
+ /**
+ * Whether fullscreen option in per-app user aspect ratio settings is enabled
+ */
+ @VisibleForTesting
+ boolean isFullscreenOptionEnabled() {
+ final boolean isBuildTimeFlagEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_appCompatUserAppAspectRatioFullscreenIsEnabled);
+ return isBuildTimeFlagEnabled && getValueFromDeviceConfig(
+ KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN,
+ DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN);
+ }
+
+ private static boolean getValueFromDeviceConfig(String name, boolean defaultValue) {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, name, defaultValue);
}
@NonNull
@@ -122,14 +171,18 @@ public class UserAspectRatioManager {
final Map userMinAspectRatioMap = new ArrayMap<>();
for (int i = 0; i < userMinAspectRatioValues.length; i++) {
final int aspectRatioVal = userMinAspectRatioValues[i];
+ final String aspectRatioString = getAspectRatioStringOrDefault(
+ userMinAspectRatioStrings[i], aspectRatioVal);
switch (aspectRatioVal) {
// Only map known values of UserMinAspectRatio and ignore unknown entries
+ case PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN:
case PackageManager.USER_MIN_ASPECT_RATIO_UNSET:
case PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
+ case PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE:
case PackageManager.USER_MIN_ASPECT_RATIO_4_3:
case PackageManager.USER_MIN_ASPECT_RATIO_16_9:
case PackageManager.USER_MIN_ASPECT_RATIO_3_2:
- userMinAspectRatioMap.put(aspectRatioVal, userMinAspectRatioStrings[i]);
+ userMinAspectRatioMap.put(aspectRatioVal, aspectRatioString);
}
}
if (!userMinAspectRatioMap.containsKey(PackageManager.USER_MIN_ASPECT_RATIO_UNSET)) {
@@ -139,6 +192,31 @@ public class UserAspectRatioManager {
return userMinAspectRatioMap;
}
+ @NonNull
+ private String getAspectRatioStringOrDefault(@Nullable String aspectRatioString,
+ @PackageManager.UserMinAspectRatio int aspectRatioVal) {
+ if (aspectRatioString != null) {
+ return aspectRatioString;
+ }
+ // Options are customized per device and if strings are set to @null, use default
+ switch (aspectRatioVal) {
+ case PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN:
+ return mContext.getString(R.string.user_aspect_ratio_fullscreen);
+ case PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
+ return mContext.getString(R.string.user_aspect_ratio_half_screen);
+ case PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE:
+ return mContext.getString(R.string.user_aspect_ratio_device_size);
+ case PackageManager.USER_MIN_ASPECT_RATIO_4_3:
+ return mContext.getString(R.string.user_aspect_ratio_4_3);
+ case PackageManager.USER_MIN_ASPECT_RATIO_16_9:
+ return mContext.getString(R.string.user_aspect_ratio_16_9);
+ case PackageManager.USER_MIN_ASPECT_RATIO_3_2:
+ return mContext.getString(R.string.user_aspect_ratio_3_2);
+ default:
+ return mContext.getString(R.string.user_aspect_ratio_app_default);
+ }
+ }
+
@VisibleForTesting
void addInfoHasLauncherEntry(@NonNull ResolveInfo infoHasLauncherEntry) {
mInfoHasLauncherEntryList.add(infoHasLauncherEntry);
diff --git a/src/com/android/settings/dream/WhenToDreamPicker.java b/src/com/android/settings/dream/WhenToDreamPicker.java
index 13cdadf1981..3052d20ba71 100644
--- a/src/com/android/settings/dream/WhenToDreamPicker.java
+++ b/src/com/android/settings/dream/WhenToDreamPicker.java
@@ -50,7 +50,7 @@ public class WhenToDreamPicker extends RadioButtonPickerFragment {
@Override
public int getMetricsCategory() {
- return SettingsEnums.DREAM;
+ return SettingsEnums.SETTINGS_WHEN_TO_DREAM;
}
@Override
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index c06e7f023d9..d345be9c194 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.util.ArrayMap;
import android.util.SparseIntArray;
@@ -129,9 +130,14 @@ public interface PowerUsageFeatureProvider {
boolean delayHourlyJobWhenBooting();
/**
- * Insert device usage data for anomaly detection
+ * Insert settings configuration data for anomaly detection
*/
- void insertSettingsData(Context context);
+ void insertSettingsData(Context context, double displayDrain);
+
+ /**
+ * Returns {@link Bundle} for settings anomaly detection result
+ */
+ Bundle detectSettingsAnomaly(Context context, double displayDrain);
/**
* Gets an intent for one time bypass charge limited to resume charging.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 89d793a9e92..e4c6fd9dc70 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -21,6 +21,7 @@ import static com.android.settings.Utils.SYSTEMUI_PACKAGE_NAME;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.Bundle;
import android.os.Process;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -161,7 +162,12 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
}
@Override
- public void insertSettingsData(Context context) {}
+ public void insertSettingsData(Context context, double displayDrain) {}
+
+ @Override
+ public Bundle detectSettingsAnomaly(Context context, double displayDrain) {
+ return null;
+ }
@Override
public Set getOthersSystemComponentSet() {
diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
index 254cf046bb8..e08f4ba56db 100644
--- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.ComponentName;
import android.content.Context;
+import android.os.BatteryManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -139,7 +140,10 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle
if (Utils.containsIncompatibleChargers(mContext, TAG)) {
return mContext.getString(R.string.battery_info_status_not_charging);
}
- if (!info.discharging && info.chargeLabel != null) {
+ if (info.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
+ // Present status only if no remaining time or status anomalous
+ return info.statusLabel;
+ } else if (!info.discharging && info.chargeLabel != null) {
return info.chargeLabel;
} else if (info.remainingLabel == null) {
return info.batteryPercentString;
diff --git a/src/com/android/settings/fuelgauge/protos/Android.bp b/src/com/android/settings/fuelgauge/protos/Android.bp
index 3af2aef0796..1f3cdd98b02 100644
--- a/src/com/android/settings/fuelgauge/protos/Android.bp
+++ b/src/com/android/settings/fuelgauge/protos/Android.bp
@@ -30,3 +30,11 @@ java_library {
},
srcs: ["fuelgauge_usage_state.proto"],
}
+
+java_library {
+ name: "power-anomaly-event-protos-lite",
+ proto: {
+ type: "lite",
+ },
+ srcs: ["power_anomaly_event.proto"],
+}
diff --git a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
new file mode 100644
index 00000000000..b4277c4bcc6
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -0,0 +1,37 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.android.settings.fuelgauge.batteryusage";
+option java_outer_classname = "PowerAnomalyEventProto";
+
+message PowerAnomalyEvent {
+ optional int64 timestamp = 1;
+ optional string type = 2; // e.g. settings, apps
+ optional string key = 3; // e.g. brightness, significant_increase
+ optional float score = 4;
+ oneof info {
+ WarningBannerInfo warning_banner_info = 5;
+ WarningItemInfo warning_item_info = 6;
+ }
+}
+
+message WarningBannerInfo {
+ optional string title_string = 1;
+ optional string description_string = 2;
+ optional string main_button_string = 3;
+ optional string main_button_action = 4;
+ optional string cancel_button_string = 5;
+ optional string cancel_button_action = 6;
+}
+
+message WarningItemInfo {
+ optional int64 start_timestamp = 1;
+ optional int64 end_timestamp = 2;
+ optional string top_card_string = 3;
+ optional string title_string = 4;
+ optional string description_string = 5;
+ optional string main_button_string = 6;
+ optional string main_button_action = 7;
+ optional string cancel_button_string = 8;
+ optional string cancel_button_action = 9;
+}
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
new file mode 100644
index 00000000000..3680715705e
--- /dev/null
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.app.appcompat
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.settings.R
+import com.android.settings.applications.appcompat.UserAspectRatioDetails
+import com.android.settings.applications.appcompat.UserAspectRatioManager
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
+
+@OptIn(ExperimentalLifecycleComposeApi::class)
+@Composable
+fun UserAspectRatioAppPreference(app: ApplicationInfo) {
+ val context = LocalContext.current
+ val presenter = remember { UserAspectRatioAppPresenter(context, app) }
+ if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
+
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.aspect_ratio_title)
+ override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
+ initialValue = stringResource(R.string.summary_placeholder),
+ )
+ override val onClick = presenter::startActivity
+ })
+}
+
+class UserAspectRatioAppPresenter(
+ private val context: Context,
+ private val app: ApplicationInfo,
+) {
+ private val manager = UserAspectRatioManager(context)
+
+ val isAvailableFlow = flow {
+ emit(UserAspectRatioManager.isFeatureEnabled(context)
+ && manager.canDisplayAspectRatioUi(app))
+ }.flowOn(Dispatchers.IO)
+
+ fun startActivity() =
+ navigateToAppAspectRatioSettings(context, app)
+
+ val summaryFlow = flow {
+ emit(manager.getUserMinAspectRatioEntry(app.packageName, context.userId))
+ }.flowOn(Dispatchers.IO)
+}
+
+fun navigateToAppAspectRatioSettings(context: Context, app: ApplicationInfo) {
+ AppInfoDashboardFragment.startAppInfoFragment(
+ UserAspectRatioDetails::class.java,
+ app,
+ context,
+ AppInfoSettingsProvider.METRICS_CATEGORY,
+ )
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index 34b6b663066..ff904921ec6 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -36,7 +36,6 @@ import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
import com.android.settings.applications.appcompat.UserAspectRatioManager
-import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
@@ -81,7 +80,7 @@ object UserAspectRatioAppsPageProvider : SettingsPageProvider {
@VisibleForTesting
fun EntryItem() =
Preference(object : PreferenceModel {
- override val title = stringResource(R.string.screen_size_title)
+ override val title = stringResource(R.string.aspect_ratio_title)
override val summary = getSummary().toState()
override val onClick = navigator(name)
})
@@ -94,7 +93,7 @@ object UserAspectRatioAppsPageProvider : SettingsPageProvider {
@Composable
@VisibleForTesting
- fun getSummary(): String = stringResource(R.string.screen_size_summary, Build.MODEL)
+ fun getSummary(): String = stringResource(R.string.aspect_ratio_summary, Build.MODEL)
}
@Composable
@@ -103,7 +102,7 @@ fun UserAspectRatioAppList(
= { AppList() },
) {
AppListPage(
- title = stringResource(R.string.screen_size_title),
+ title = stringResource(R.string.aspect_ratio_title),
listModel = rememberContext(::UserAspectRatioAppListModel),
appList = appList,
header = {
@@ -148,7 +147,7 @@ class UserAspectRatioAppListModel(private val context: Context)
override fun AppListItemModel.AppItem() {
val app = record.app
AppListItem(
- onClick = AppInfoSettingsProvider.navigator(app)
+ onClick = { navigateToAppAspectRatioSettings(context, app) }
)
}
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index d59a4f72c86..e6df933df1f 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -35,6 +35,7 @@ import com.android.settings.R
import com.android.settings.applications.AppInfoBase
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
+import com.android.settings.spa.app.appcompat.UserAspectRatioAppPreference
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
@@ -150,6 +151,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
}
Category(title = stringResource(R.string.advanced_apps)) {
+ UserAspectRatioAppPreference(app)
DisplayOverOtherAppsAppListProvider.InfoPageEntryItem(app)
ModifySystemSettingsAppListProvider.InfoPageEntryItem(app)
PictureInPictureListProvider.InfoPageEntryItem(app)
diff --git a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
new file mode 100644
index 00000000000..31ff76c7d11
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appcompat;
+
+import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_3_2;
+import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_DEFAULT;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.content.Context;
+import android.os.RemoteException;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.testutils.shadow.ShadowActivityManager;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+/**
+ * To run test: atest SettingsRoboTests:UserAspectRatioDetailsTest
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowActivityManager.class})
+public class UserAspectRatioDetailsTest {
+
+ @Mock
+ private UserAspectRatioManager mUserAspectRatioManager;
+ @Mock
+ private IActivityManager mAm;
+
+ private SelectorWithWidgetPreference mRadioButtonPref;
+ private Context mContext;
+ private UserAspectRatioDetails mFragment;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mFragment = spy(new UserAspectRatioDetails());
+ when(mFragment.getContext()).thenReturn(mContext);
+ when(mFragment.getAspectRatioManager()).thenReturn(mUserAspectRatioManager);
+ ShadowActivityManager.setService(mAm);
+ mRadioButtonPref = new SelectorWithWidgetPreference(mContext);
+ }
+
+ @Test
+ public void onRadioButtonClicked_prefChange_shouldStopActivity() throws RemoteException {
+ // Default was already selected
+ mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
+ mFragment.onRadioButtonClicked(mRadioButtonPref);
+ // Preference changed
+ mRadioButtonPref.setKey(KEY_PREF_3_2);
+ mFragment.onRadioButtonClicked(mRadioButtonPref);
+ // Only triggered once when preference change
+ verify(mAm).stopAppForUser(any(), anyInt());
+ }
+
+ @Test
+ public void onRadioButtonClicked_prefChange_shouldSetAspectRatio() throws RemoteException {
+ // Default was already selected
+ mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
+ mFragment.onRadioButtonClicked(mRadioButtonPref);
+ // Preference changed
+ mRadioButtonPref.setKey(KEY_PREF_3_2);
+ mFragment.onRadioButtonClicked(mRadioButtonPref);
+ // Only triggered once when preference changes
+ verify(mUserAspectRatioManager).setUserMinAspectRatio(
+ any(), anyInt(), anyInt());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
index b44430973a3..f6bc2975f34 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
@@ -31,6 +31,7 @@ import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.os.BatteryManager;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
@@ -145,6 +146,17 @@ public class TopLevelBatteryPreferenceControllerTest {
.isEqualTo(mContext.getString(R.string.battery_info_status_not_charging));
}
+ @Test
+ public void getDashboardLabel_notChargingState_returnsCorrectLabel() {
+ mController.mPreference = new Preference(mContext);
+ BatteryInfo info = new BatteryInfo();
+ info.batteryStatus = BatteryManager.BATTERY_STATUS_NOT_CHARGING;
+ info.statusLabel = "expected returned label";
+
+ assertThat(mController.getDashboardLabel(mContext, info, true))
+ .isEqualTo(info.statusLabel);
+ }
+
@Test
public void getSummary_batteryNotPresent_shouldShowWarningMessage() {
mController.mIsBatteryPresent = false;
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
new file mode 100644
index 00000000000..342405acf9d
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.app.appcompat
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.os.Build
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasTextExactly
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER
+import com.android.settings.R
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment
+import com.android.settings.applications.appcompat.UserAspectRatioDetails
+import com.android.settings.applications.appcompat.UserAspectRatioManager
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
+import com.android.settings.testutils.TestDeviceConfig
+import com.android.settingslib.spa.testutils.delay
+import com.android.settingslib.spa.testutils.waitUntilExists
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.MockitoSession
+import org.mockito.Spy
+import org.mockito.quality.Strictness
+import org.mockito.Mockito.`when` as whenever
+
+/**
+ * To run this test: atest SettingsSpaUnitTests:UserAspectRatioAppPreferenceTest
+ */
+@RunWith(AndroidJUnit4::class)
+class UserAspectRatioAppPreferenceTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private lateinit var mockSession: MockitoSession
+
+ @Spy
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Spy
+ private val resources = context.resources
+
+ private val aspectRatioEnabledConfig =
+ TestDeviceConfig(NAMESPACE_WINDOW_MANAGER, "enable_app_compat_user_aspect_ratio_settings")
+
+ private lateinit var userAspectRatioManager: UserAspectRatioManager
+
+ @Mock
+ private lateinit var packageManager: PackageManager
+
+ @Before
+ fun setUp() {
+ mockSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .mockStatic(UserAspectRatioDetails::class.java)
+ .mockStatic(AppInfoDashboardFragment::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ whenever(context.resources).thenReturn(resources)
+ whenever(context.packageManager).thenReturn(packageManager)
+ userAspectRatioManager = mock(UserAspectRatioManager::class.java)
+ }
+
+ @After
+ fun tearDown() {
+ aspectRatioEnabledConfig.reset()
+ mockSession.finishMocking()
+ }
+
+ @Test
+ fun whenConfigIsFalse_notDisplayed() {
+ setConfig(false)
+
+ setContent()
+
+ composeTestRule.onRoot().assertIsNotDisplayed()
+ }
+
+ @Test
+ fun whenCannotDisplayAspectRatioUi_notDisplayed() {
+ setContent()
+
+ composeTestRule.onRoot().assertIsNotDisplayed()
+ }
+
+ @Test
+ fun whenCanDisplayAspectRatioUiAndConfigFalse_notDisplayed() {
+ setConfig(false)
+ whenever(packageManager.queryIntentActivities(any(), anyInt()))
+ .thenReturn(listOf(RESOLVE_INFO))
+
+ setContent()
+
+ composeTestRule.onRoot().assertIsNotDisplayed()
+ }
+
+ @Test
+ fun whenCannotDisplayAspectRatioUiAndConfigTrue_notDisplayed() {
+ setConfig(true)
+
+ setContent()
+
+ composeTestRule.onRoot().assertIsNotDisplayed()
+ }
+
+ @Test
+ fun whenCanDisplayAspectRatioUiAndConfigTrue_Displayed() {
+ setConfig(true)
+ whenever(packageManager.queryIntentActivities(any(), anyInt()))
+ .thenReturn(listOf(RESOLVE_INFO))
+
+ setContent()
+
+ composeTestRule.onNode(
+ hasTextExactly(
+ context.getString(R.string.aspect_ratio_title),
+ context.getString(R.string.user_aspect_ratio_app_default)
+ ),
+ ).assertIsDisplayed().assertIsEnabled()
+ }
+
+ @Test
+ fun onClick_startActivity() {
+ setConfig(true)
+ whenever(packageManager.queryIntentActivities(any(), anyInt()))
+ .thenReturn(listOf(RESOLVE_INFO))
+
+ setContent()
+ composeTestRule.onRoot().performClick()
+
+ ExtendedMockito.verify {
+ AppInfoDashboardFragment.startAppInfoFragment(
+ UserAspectRatioDetails::class.java,
+ APP,
+ context,
+ AppInfoSettingsProvider.METRICS_CATEGORY,
+ )
+ }
+ }
+
+ private fun setConfig(enabled: Boolean) {
+ whenever(resources.getBoolean(
+ com.android.internal.R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled
+ )).thenReturn(enabled)
+ aspectRatioEnabledConfig.override(enabled)
+ }
+
+ private fun setContent() {
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ UserAspectRatioAppPreference(APP)
+ }
+ }
+ composeTestRule.delay()
+ }
+
+ private companion object {
+ const val PACKAGE_NAME = "package.name"
+ const val UID = 123
+ val APP = ApplicationInfo().apply {
+ packageName = PACKAGE_NAME
+ uid = UID
+ }
+ private val RESOLVE_INFO = ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply {
+ packageName = PACKAGE_NAME
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index e0eb5b2c86a..0d2869c6cdf 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -60,21 +60,21 @@ class UserAspectRatioAppsPageProviderTest {
@Test
fun injectEntry_title() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.screen_size_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
.assertIsDisplayed()
}
@Test
fun injectEntry_summary() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.screen_size_summary, Build.MODEL))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_summary, Build.MODEL))
.assertIsDisplayed()
}
@Test
fun injectEntry_onClick_navigate() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.screen_size_title)).performClick()
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title)).performClick()
assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
}
@@ -92,7 +92,7 @@ class UserAspectRatioAppsPageProviderTest {
UserAspectRatioAppList {}
}
- composeTestRule.onNodeWithText(context.getString(R.string.screen_size_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
.assertIsDisplayed()
}
diff --git a/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java b/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
index 36f2f54e2c5..f4dcaf8ff2e 100644
--- a/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
+++ b/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
@@ -19,9 +19,11 @@ package com.android.settings.applications.appcompat;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
+import static com.android.settings.applications.appcompat.UserAspectRatioManager.KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN;
import static com.android.settings.applications.appcompat.UserAspectRatioManager.KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
@@ -30,16 +32,19 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.provider.DeviceConfig;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.R;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.After;
@@ -54,21 +59,35 @@ import org.junit.runner.RunWith;
public class UserAspectRatioManagerTest {
private Context mContext;
+ private Resources mResources;
private UserAspectRatioManager mUtils;
- private String mOriginalFlag;
+ private String mOriginalSettingsFlag;
+ private String mOriginalFullscreenFlag;
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
+ mResources = spy(mContext.getResources());
mUtils = spy(new UserAspectRatioManager(mContext));
- mOriginalFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS);
+
+ when(mContext.getResources()).thenReturn(mResources);
+
+ mOriginalSettingsFlag = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS);
+ setAspectRatioSettingsBuildTimeFlagEnabled(true);
+ setAspectRatioSettingsDeviceConfigEnabled("true" /* enabled */, false /* makeDefault */);
+
+ mOriginalFullscreenFlag = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN);
+ setAspectRatioFullscreenBuildTimeFlagEnabled(true);
+ setAspectRatioFullscreenDeviceConfigEnabled("true" /* enabled */, false /* makeDefault */);
}
@After
public void tearDown() {
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, mOriginalFlag, true /* makeDefault */);
+ setAspectRatioSettingsDeviceConfigEnabled(mOriginalSettingsFlag, true /* makeDefault */);
+ setAspectRatioFullscreenDeviceConfigEnabled(mOriginalFullscreenFlag,
+ true /* makeDefault */);
}
@Test
@@ -87,13 +106,52 @@ public class UserAspectRatioManagerTest {
@Test
public void testIsFeatureEnabled() {
- assertFalse(UserAspectRatioManager.isFeatureEnabled(mContext));
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, "true", false /* makeDefault */);
assertTrue(UserAspectRatioManager.isFeatureEnabled(mContext));
}
+ @Test
+ public void testIsFeatureEnabled_disabledBuildTimeFlag_returnFalse() {
+ setAspectRatioSettingsBuildTimeFlagEnabled(false);
+ assertFalse(UserAspectRatioManager.isFeatureEnabled(mContext));
+ }
+
+ @Test
+ public void testIsFeatureEnabled_disabledRuntimeFlag_returnFalse() {
+ setAspectRatioSettingsDeviceConfigEnabled("false" /* enabled */, false /* makeDefault */);
+ assertFalse(UserAspectRatioManager.isFeatureEnabled(mContext));
+ }
+
+ @Test
+ public void testIsFullscreenOptionEnabled() {
+ assertTrue(mUtils.isFullscreenOptionEnabled());
+ }
+
+ @Test
+ public void testIsFullscreenOptionEnabled_settingsDisabled_returnFalse() {
+ setAspectRatioFullscreenBuildTimeFlagEnabled(false);
+ assertFalse(mUtils.isFullscreenOptionEnabled());
+ }
+
+ @Test
+ public void testIsFullscreenOptionEnabled_disabledBuildTimeFlag_returnFalse() {
+ setAspectRatioFullscreenBuildTimeFlagEnabled(false);
+ assertFalse(mUtils.isFullscreenOptionEnabled());
+ }
+
+ @Test
+ public void testIsFullscreenOptionEnabled_disabledRuntimeFlag_returnFalse() {
+ setAspectRatioFullscreenDeviceConfigEnabled("false" /* enabled */, false /*makeDefault */);
+ assertFalse(mUtils.isFullscreenOptionEnabled());
+ }
+
+ @Test
+ public void containsAspectRatioOption_fullscreen() {
+ assertTrue(mUtils.containsAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN));
+
+ when(mUtils.isFullscreenOptionEnabled()).thenReturn(false);
+ assertFalse(mUtils.containsAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN));
+ }
+
@Test
public void testGetUserMinAspectRatioEntry() {
// R.string.user_aspect_ratio_app_default
@@ -117,6 +175,38 @@ public class UserAspectRatioManagerTest {
// R.string.user_aspect_ratio_16_9
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_16_9))
.isEqualTo(ResourcesUtils.getResourcesString(mContext, "user_aspect_ratio_16_9"));
+ // R.string.user_aspect_ratio_fullscreen
+ assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN))
+ .isEqualTo(ResourcesUtils.getResourcesString(mContext,
+ "user_aspect_ratio_fullscreen"));
+ }
+
+ @Test
+ public void testGetUserMinAspectRatioEntry_fullscreenDisabled_shouldReturnDefault() {
+ setAspectRatioFullscreenBuildTimeFlagEnabled(false);
+ assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN))
+ .isEqualTo(ResourcesUtils.getResourcesString(mContext,
+ "user_aspect_ratio_app_default"));
+ }
+
+ private void setAspectRatioSettingsBuildTimeFlagEnabled(boolean enabled) {
+ when(mResources.getBoolean(R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled))
+ .thenReturn(enabled);
+ }
+
+ private void setAspectRatioSettingsDeviceConfigEnabled(String enabled, boolean makeDefault) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, enabled, makeDefault);
+ }
+
+ private void setAspectRatioFullscreenBuildTimeFlagEnabled(boolean enabled) {
+ when(mResources.getBoolean(R.bool.config_appCompatUserAppAspectRatioFullscreenIsEnabled))
+ .thenReturn(enabled);
+ }
+
+ private void setAspectRatioFullscreenDeviceConfigEnabled(String enabled, boolean makeDefault) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, enabled, makeDefault);
}
private void addResolveInfoLauncherEntry(String packageName) {