Loading src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java +38 −37 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ 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_APP_DEFAULT; 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; Loading Loading @@ -51,6 +52,9 @@ import com.android.settingslib.applications.AppUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.widget.ActionButtonsPreference; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.util.ArrayList; import java.util.List; Loading @@ -63,29 +67,41 @@ public class UserAspectRatioDetails extends AppInfoBase implements private static final String KEY_HEADER_SUMMARY = "app_aspect_ratio_summary"; 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_FULLSCREEN = "fullscreen_pref"; @VisibleForTesting static final String KEY_PREF_DEFAULT = "app_default_pref"; @VisibleForTesting static final String KEY_PREF_3_2 = "3_2_pref"; @VisibleForTesting @NonNull String mSelectedKey = KEY_PREF_DEFAULT; /** Radio button preference key mapped to {@link PackageManager.UserMinAspectRatio} value */ @VisibleForTesting final BiMap<String, Integer> mKeyToAspectRatioMap = HashBiMap.create(); private final List<RadioWithImagePreference> mAspectRatioPreferences = new ArrayList<>(); @NonNull private UserAspectRatioManager mUserAspectRatioManager; @NonNull private String mSelectedKey = KEY_PREF_DEFAULT; private boolean mIsOverrideToFullscreenEnabled; @Override public void onCreate(@NonNull Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUserAspectRatioManager = new UserAspectRatioManager(getContext()); mIsOverrideToFullscreenEnabled = getAspectRatioManager() .isOverrideToFullscreenEnabled(mPackageName, mUserId); initPreferences(); try { final int userAspectRatio = mUserAspectRatioManager final int userAspectRatio = getAspectRatioManager() .getUserMinAspectRatioValue(mPackageName, mUserId); mSelectedKey = getSelectedKey(userAspectRatio); } catch (RemoteException e) { Loading Loading @@ -148,43 +164,23 @@ public class UserAspectRatioDetails extends AppInfoBase implements } @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; } @VisibleForTesting int getSelectedUserMinAspectRatio(@NonNull String selectedKey) { final int appDefault = mKeyToAspectRatioMap .getOrDefault(KEY_PREF_DEFAULT, USER_MIN_ASPECT_RATIO_UNSET); return mKeyToAspectRatioMap.getOrDefault(selectedKey, appDefault); } @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; final String appDefault = mKeyToAspectRatioMap.inverse() .getOrDefault(USER_MIN_ASPECT_RATIO_UNSET, KEY_PREF_DEFAULT); if (userMinAspectRatio == USER_MIN_ASPECT_RATIO_UNSET && mIsOverrideToFullscreenEnabled) { // Pre-select fullscreen option if device manufacturer has overridden app to fullscreen userMinAspectRatio = USER_MIN_ASPECT_RATIO_FULLSCREEN; } return mKeyToAspectRatioMap.inverse().getOrDefault(userMinAspectRatio, appDefault); } @Override Loading Loading @@ -217,7 +213,11 @@ public class UserAspectRatioDetails extends AppInfoBase implements .setButton1Icon(R.drawable.ic_settings_open) .setButton1OnClickListener(v -> launchApplication()); if (mIsOverrideToFullscreenEnabled) { addPreference(KEY_PREF_DEFAULT, USER_MIN_ASPECT_RATIO_APP_DEFAULT); } else { 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); Loading @@ -232,12 +232,13 @@ public class UserAspectRatioDetails extends AppInfoBase implements if (pref == null) { return; } if (!mUserAspectRatioManager.hasAspectRatioOption(aspectRatio, mPackageName)) { if (!getAspectRatioManager().hasAspectRatioOption(aspectRatio, mPackageName)) { pref.setVisible(false); return; } pref.setTitle(mUserAspectRatioManager.getAccessibleEntry(aspectRatio, mPackageName)); pref.setOnClickListener(this); mKeyToAspectRatioMap.put(key, aspectRatio); mAspectRatioPreferences.add(pref); } Loading src/com/android/settings/applications/appcompat/UserAspectRatioManager.java +104 −28 Original line number Diff line number Diff line Loading @@ -16,19 +16,32 @@ package com.android.settings.applications.appcompat; import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER; 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_APP_DEFAULT; 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 static android.os.UserHandle.getUserHandleForUid; import static android.os.UserHandle.getUserId; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE; import static java.lang.Boolean.FALSE; import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import android.util.ArrayMap; Loading @@ -37,6 +50,7 @@ import androidx.annotation.Nullable; import com.android.settings.R; import com.android.settings.Utils; import com.android.window.flags.Flags; import com.google.common.annotations.VisibleForTesting; Loading @@ -55,6 +69,8 @@ public class UserAspectRatioManager { "enable_app_compat_user_aspect_ratio_fullscreen"; private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true; final boolean mIsUserMinAspectRatioAppDefaultFlagEnabled = Flags.userMinAspectRatioAppDefault(); private final Context mContext; private final IPackageManager mIPm; /** Apps that have launcher entry defined in manifest */ Loading @@ -62,8 +78,13 @@ public class UserAspectRatioManager { private final Map<Integer, CharSequence> mUserAspectRatioA11yMap; public UserAspectRatioManager(@NonNull Context context) { this(context, AppGlobals.getPackageManager()); } @VisibleForTesting UserAspectRatioManager(@NonNull Context context, @NonNull IPackageManager pm) { mContext = context; mIPm = AppGlobals.getPackageManager(); mIPm = pm; mUserAspectRatioA11yMap = new ArrayMap<>(); mUserAspectRatioMap = getUserMinAspectRatioMapping(); } Loading @@ -86,7 +107,7 @@ public class UserAspectRatioManager { throws RemoteException { final int aspectRatio = mIPm.getUserMinAspectRatio(packageName, uid); return hasAspectRatioOption(aspectRatio, packageName) ? aspectRatio : PackageManager.USER_MIN_ASPECT_RATIO_UNSET; ? aspectRatio : USER_MIN_ASPECT_RATIO_UNSET; } /** Loading @@ -94,11 +115,18 @@ public class UserAspectRatioManager { */ @NonNull public String getUserMinAspectRatioEntry(@PackageManager.UserMinAspectRatio int aspectRatio, String packageName) { @NonNull String packageName, int userId) { final String appDefault = getAspectRatioStringOrDefault( mUserAspectRatioMap.get(USER_MIN_ASPECT_RATIO_UNSET), USER_MIN_ASPECT_RATIO_UNSET); if (!hasAspectRatioOption(aspectRatio, packageName)) { return mUserAspectRatioMap.get(PackageManager.USER_MIN_ASPECT_RATIO_UNSET); return appDefault; } return mUserAspectRatioMap.get(aspectRatio); return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio) ? getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName, userId) : mUserAspectRatioMap.getOrDefault(aspectRatio, appDefault); } /** Loading @@ -106,19 +134,22 @@ public class UserAspectRatioManager { */ @NonNull public CharSequence getAccessibleEntry(@PackageManager.UserMinAspectRatio int aspectRatio, String packageName) { return mUserAspectRatioA11yMap.getOrDefault(aspectRatio, getUserMinAspectRatioEntry(aspectRatio, packageName)); @NonNull String packageName) { final int userId = mContext.getUserId(); return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio) ? getAccessibleEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName) : mUserAspectRatioA11yMap.getOrDefault(aspectRatio, getUserMinAspectRatioEntry(aspectRatio, packageName, userId)); } /** * @return corresponding aspect ratio string for package name and user */ @NonNull public String getUserMinAspectRatioEntry(@NonNull String packageName, int uid) public String getUserMinAspectRatioEntry(@NonNull String packageName, int userId) throws RemoteException { final int aspectRatio = getUserMinAspectRatioValue(packageName, uid); return getUserMinAspectRatioEntry(aspectRatio, packageName); final int aspectRatio = getUserMinAspectRatioValue(packageName, userId); return getUserMinAspectRatioEntry(aspectRatio, packageName, userId); } /** Loading @@ -128,8 +159,7 @@ public class UserAspectRatioManager { */ public boolean hasAspectRatioOption(@PackageManager.UserMinAspectRatio int option, String packageName) { if (option == PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN && !isFullscreenOptionEnabled(packageName)) { if (option == USER_MIN_ASPECT_RATIO_FULLSCREEN && !isFullscreenOptionEnabled(packageName)) { return false; } return mUserAspectRatioMap.containsKey(option); Loading @@ -154,6 +184,18 @@ public class UserAspectRatioManager { return !FALSE.equals(appAllowsUserAspectRatioOverride) && hasLauncherEntry(app); } /** * Whether the app has been overridden to fullscreen by device manufacturer or * whether the app's aspect ratio has been overridden by the user. */ public boolean isAppOverridden(@NonNull ApplicationInfo app, @PackageManager.UserMinAspectRatio int userOverride) { return (userOverride != USER_MIN_ASPECT_RATIO_UNSET && userOverride != USER_MIN_ASPECT_RATIO_APP_DEFAULT) || isCurrentSelectionFromManufacturerOverride(app.packageName, getUserId(app.uid), userOverride); } /** * Whether fullscreen option in per-app user aspect ratio settings is enabled */ Loading @@ -168,6 +210,32 @@ public class UserAspectRatioManager { DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN); } /** * Whether the device manufacturer has overridden app's orientation to * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER} to force app to fullscreen * and app has not opted-out from the treatment */ boolean isOverrideToFullscreenEnabled(String pkgName, int userId) { Boolean appAllowsOrientationOverride = readComponentProperty(mContext.getPackageManager(), pkgName, PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE); return mIsUserMinAspectRatioAppDefaultFlagEnabled && hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, pkgName) && !FALSE.equals(appAllowsOrientationOverride) && isFullscreenCompatChangeEnabled(pkgName, userId); } @VisibleForTesting boolean isFullscreenCompatChangeEnabled(String pkgName, int userId) { return CompatChanges.isChangeEnabled( OVERRIDE_ANY_ORIENTATION_TO_USER, pkgName, UserHandle.of(userId)); } private boolean isCurrentSelectionFromManufacturerOverride(String pkgName, int userId, @PackageManager.UserMinAspectRatio int aspectRatio) { return aspectRatio == USER_MIN_ASPECT_RATIO_UNSET && isOverrideToFullscreenEnabled(pkgName, userId); } private boolean hasLauncherEntry(@NonNull ApplicationInfo app) { return !mContext.getSystemService(LauncherApps.class) .getActivityList(app.packageName, getUserHandleForUid(app.uid)) Loading Loading @@ -197,13 +265,13 @@ public class UserAspectRatioManager { boolean containsColon = aspectRatioString.contains(":"); 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: case USER_MIN_ASPECT_RATIO_FULLSCREEN: case USER_MIN_ASPECT_RATIO_UNSET: case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: case USER_MIN_ASPECT_RATIO_4_3: case USER_MIN_ASPECT_RATIO_16_9: case USER_MIN_ASPECT_RATIO_3_2: if (containsColon) { String[] aspectRatioDigits = aspectRatioString.split(":"); String accessibleString = getAccessibleOption(aspectRatioDigits[0], Loading @@ -215,10 +283,18 @@ public class UserAspectRatioManager { userMinAspectRatioMap.put(aspectRatioVal, aspectRatioString); } } if (!userMinAspectRatioMap.containsKey(PackageManager.USER_MIN_ASPECT_RATIO_UNSET)) { if (!userMinAspectRatioMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { throw new RuntimeException("config_userAspectRatioOverrideValues options must have" + " USER_MIN_ASPECT_RATIO_UNSET value"); } if (mIsUserMinAspectRatioAppDefaultFlagEnabled) { userMinAspectRatioMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, userMinAspectRatioMap.get(USER_MIN_ASPECT_RATIO_UNSET)); if (mUserAspectRatioA11yMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { mUserAspectRatioA11yMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, mUserAspectRatioA11yMap.get(USER_MIN_ASPECT_RATIO_UNSET)); } } return userMinAspectRatioMap; } Loading @@ -236,17 +312,17 @@ public class UserAspectRatioManager { } // Options are customized per device and if strings are set to @null, use default switch (aspectRatioVal) { case PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN: case USER_MIN_ASPECT_RATIO_FULLSCREEN: return mContext.getString(R.string.user_aspect_ratio_fullscreen); case PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: return mContext.getString(R.string.user_aspect_ratio_half_screen); case PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: return mContext.getString(R.string.user_aspect_ratio_device_size); case PackageManager.USER_MIN_ASPECT_RATIO_4_3: case USER_MIN_ASPECT_RATIO_4_3: return mContext.getString(R.string.user_aspect_ratio_4_3); case PackageManager.USER_MIN_ASPECT_RATIO_16_9: case USER_MIN_ASPECT_RATIO_16_9: return mContext.getString(R.string.user_aspect_ratio_16_9); case PackageManager.USER_MIN_ASPECT_RATIO_3_2: case 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); Loading src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt +8 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.GET_ACTIVITIES import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET import android.os.Build import android.os.Bundle Loading Loading @@ -139,7 +140,9 @@ class UserAspectRatioAppListModel(private val context: Context) recordList: List<UserAspectRatioAppListItemModel> ): List<SpinnerOption> { val hasSuggested = recordList.any { it.suggested } val hasOverride = recordList.any { it.userOverride != USER_MIN_ASPECT_RATIO_UNSET } val hasOverride = recordList.any { userAspectRatioManager.isAppOverridden(it.app, it.userOverride) } val options = mutableListOf(SpinnerItem.All) // Add suggested filter first as default if (hasSuggested) options.add(0, SpinnerItem.Suggested) Loading Loading @@ -187,7 +190,9 @@ class UserAspectRatioAppListModel(private val context: Context) ): Flow<List<UserAspectRatioAppListItemModel>> = recordListFlow.filterItem( when (SpinnerItem.entries.getOrNull(option)) { SpinnerItem.Suggested -> ({ it.canDisplay && it.suggested }) SpinnerItem.Overridden -> ({ it.userOverride != USER_MIN_ASPECT_RATIO_UNSET }) SpinnerItem.Overridden -> ({ userAspectRatioManager.isAppOverridden(it.app, it.userOverride) }) else -> ({ it.canDisplay }) } ) Loading @@ -197,7 +202,7 @@ class UserAspectRatioAppListModel(private val context: Context) val summary by remember(record.userOverride) { flow { emit(userAspectRatioManager.getUserMinAspectRatioEntry(record.userOverride, record.app.packageName)) record.app.packageName, record.app.userId)) }.flowOn(Dispatchers.IO) }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder)) return { summary } Loading tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java +70 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes tests/spa_unit/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ <uses-permission android:name="android.permission.MANAGE_APPOPS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <application android:debuggable="true"> <provider android:name="com.android.settings.slices.SettingsSliceProvider" Loading Loading
src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java +38 −37 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ 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_APP_DEFAULT; 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; Loading Loading @@ -51,6 +52,9 @@ import com.android.settingslib.applications.AppUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.widget.ActionButtonsPreference; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.util.ArrayList; import java.util.List; Loading @@ -63,29 +67,41 @@ public class UserAspectRatioDetails extends AppInfoBase implements private static final String KEY_HEADER_SUMMARY = "app_aspect_ratio_summary"; 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_FULLSCREEN = "fullscreen_pref"; @VisibleForTesting static final String KEY_PREF_DEFAULT = "app_default_pref"; @VisibleForTesting static final String KEY_PREF_3_2 = "3_2_pref"; @VisibleForTesting @NonNull String mSelectedKey = KEY_PREF_DEFAULT; /** Radio button preference key mapped to {@link PackageManager.UserMinAspectRatio} value */ @VisibleForTesting final BiMap<String, Integer> mKeyToAspectRatioMap = HashBiMap.create(); private final List<RadioWithImagePreference> mAspectRatioPreferences = new ArrayList<>(); @NonNull private UserAspectRatioManager mUserAspectRatioManager; @NonNull private String mSelectedKey = KEY_PREF_DEFAULT; private boolean mIsOverrideToFullscreenEnabled; @Override public void onCreate(@NonNull Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUserAspectRatioManager = new UserAspectRatioManager(getContext()); mIsOverrideToFullscreenEnabled = getAspectRatioManager() .isOverrideToFullscreenEnabled(mPackageName, mUserId); initPreferences(); try { final int userAspectRatio = mUserAspectRatioManager final int userAspectRatio = getAspectRatioManager() .getUserMinAspectRatioValue(mPackageName, mUserId); mSelectedKey = getSelectedKey(userAspectRatio); } catch (RemoteException e) { Loading Loading @@ -148,43 +164,23 @@ public class UserAspectRatioDetails extends AppInfoBase implements } @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; } @VisibleForTesting int getSelectedUserMinAspectRatio(@NonNull String selectedKey) { final int appDefault = mKeyToAspectRatioMap .getOrDefault(KEY_PREF_DEFAULT, USER_MIN_ASPECT_RATIO_UNSET); return mKeyToAspectRatioMap.getOrDefault(selectedKey, appDefault); } @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; final String appDefault = mKeyToAspectRatioMap.inverse() .getOrDefault(USER_MIN_ASPECT_RATIO_UNSET, KEY_PREF_DEFAULT); if (userMinAspectRatio == USER_MIN_ASPECT_RATIO_UNSET && mIsOverrideToFullscreenEnabled) { // Pre-select fullscreen option if device manufacturer has overridden app to fullscreen userMinAspectRatio = USER_MIN_ASPECT_RATIO_FULLSCREEN; } return mKeyToAspectRatioMap.inverse().getOrDefault(userMinAspectRatio, appDefault); } @Override Loading Loading @@ -217,7 +213,11 @@ public class UserAspectRatioDetails extends AppInfoBase implements .setButton1Icon(R.drawable.ic_settings_open) .setButton1OnClickListener(v -> launchApplication()); if (mIsOverrideToFullscreenEnabled) { addPreference(KEY_PREF_DEFAULT, USER_MIN_ASPECT_RATIO_APP_DEFAULT); } else { 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); Loading @@ -232,12 +232,13 @@ public class UserAspectRatioDetails extends AppInfoBase implements if (pref == null) { return; } if (!mUserAspectRatioManager.hasAspectRatioOption(aspectRatio, mPackageName)) { if (!getAspectRatioManager().hasAspectRatioOption(aspectRatio, mPackageName)) { pref.setVisible(false); return; } pref.setTitle(mUserAspectRatioManager.getAccessibleEntry(aspectRatio, mPackageName)); pref.setOnClickListener(this); mKeyToAspectRatioMap.put(key, aspectRatio); mAspectRatioPreferences.add(pref); } Loading
src/com/android/settings/applications/appcompat/UserAspectRatioManager.java +104 −28 Original line number Diff line number Diff line Loading @@ -16,19 +16,32 @@ package com.android.settings.applications.appcompat; import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER; 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_APP_DEFAULT; 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 static android.os.UserHandle.getUserHandleForUid; import static android.os.UserHandle.getUserId; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE; import static java.lang.Boolean.FALSE; import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import android.util.ArrayMap; Loading @@ -37,6 +50,7 @@ import androidx.annotation.Nullable; import com.android.settings.R; import com.android.settings.Utils; import com.android.window.flags.Flags; import com.google.common.annotations.VisibleForTesting; Loading @@ -55,6 +69,8 @@ public class UserAspectRatioManager { "enable_app_compat_user_aspect_ratio_fullscreen"; private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true; final boolean mIsUserMinAspectRatioAppDefaultFlagEnabled = Flags.userMinAspectRatioAppDefault(); private final Context mContext; private final IPackageManager mIPm; /** Apps that have launcher entry defined in manifest */ Loading @@ -62,8 +78,13 @@ public class UserAspectRatioManager { private final Map<Integer, CharSequence> mUserAspectRatioA11yMap; public UserAspectRatioManager(@NonNull Context context) { this(context, AppGlobals.getPackageManager()); } @VisibleForTesting UserAspectRatioManager(@NonNull Context context, @NonNull IPackageManager pm) { mContext = context; mIPm = AppGlobals.getPackageManager(); mIPm = pm; mUserAspectRatioA11yMap = new ArrayMap<>(); mUserAspectRatioMap = getUserMinAspectRatioMapping(); } Loading @@ -86,7 +107,7 @@ public class UserAspectRatioManager { throws RemoteException { final int aspectRatio = mIPm.getUserMinAspectRatio(packageName, uid); return hasAspectRatioOption(aspectRatio, packageName) ? aspectRatio : PackageManager.USER_MIN_ASPECT_RATIO_UNSET; ? aspectRatio : USER_MIN_ASPECT_RATIO_UNSET; } /** Loading @@ -94,11 +115,18 @@ public class UserAspectRatioManager { */ @NonNull public String getUserMinAspectRatioEntry(@PackageManager.UserMinAspectRatio int aspectRatio, String packageName) { @NonNull String packageName, int userId) { final String appDefault = getAspectRatioStringOrDefault( mUserAspectRatioMap.get(USER_MIN_ASPECT_RATIO_UNSET), USER_MIN_ASPECT_RATIO_UNSET); if (!hasAspectRatioOption(aspectRatio, packageName)) { return mUserAspectRatioMap.get(PackageManager.USER_MIN_ASPECT_RATIO_UNSET); return appDefault; } return mUserAspectRatioMap.get(aspectRatio); return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio) ? getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName, userId) : mUserAspectRatioMap.getOrDefault(aspectRatio, appDefault); } /** Loading @@ -106,19 +134,22 @@ public class UserAspectRatioManager { */ @NonNull public CharSequence getAccessibleEntry(@PackageManager.UserMinAspectRatio int aspectRatio, String packageName) { return mUserAspectRatioA11yMap.getOrDefault(aspectRatio, getUserMinAspectRatioEntry(aspectRatio, packageName)); @NonNull String packageName) { final int userId = mContext.getUserId(); return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio) ? getAccessibleEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName) : mUserAspectRatioA11yMap.getOrDefault(aspectRatio, getUserMinAspectRatioEntry(aspectRatio, packageName, userId)); } /** * @return corresponding aspect ratio string for package name and user */ @NonNull public String getUserMinAspectRatioEntry(@NonNull String packageName, int uid) public String getUserMinAspectRatioEntry(@NonNull String packageName, int userId) throws RemoteException { final int aspectRatio = getUserMinAspectRatioValue(packageName, uid); return getUserMinAspectRatioEntry(aspectRatio, packageName); final int aspectRatio = getUserMinAspectRatioValue(packageName, userId); return getUserMinAspectRatioEntry(aspectRatio, packageName, userId); } /** Loading @@ -128,8 +159,7 @@ public class UserAspectRatioManager { */ public boolean hasAspectRatioOption(@PackageManager.UserMinAspectRatio int option, String packageName) { if (option == PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN && !isFullscreenOptionEnabled(packageName)) { if (option == USER_MIN_ASPECT_RATIO_FULLSCREEN && !isFullscreenOptionEnabled(packageName)) { return false; } return mUserAspectRatioMap.containsKey(option); Loading @@ -154,6 +184,18 @@ public class UserAspectRatioManager { return !FALSE.equals(appAllowsUserAspectRatioOverride) && hasLauncherEntry(app); } /** * Whether the app has been overridden to fullscreen by device manufacturer or * whether the app's aspect ratio has been overridden by the user. */ public boolean isAppOverridden(@NonNull ApplicationInfo app, @PackageManager.UserMinAspectRatio int userOverride) { return (userOverride != USER_MIN_ASPECT_RATIO_UNSET && userOverride != USER_MIN_ASPECT_RATIO_APP_DEFAULT) || isCurrentSelectionFromManufacturerOverride(app.packageName, getUserId(app.uid), userOverride); } /** * Whether fullscreen option in per-app user aspect ratio settings is enabled */ Loading @@ -168,6 +210,32 @@ public class UserAspectRatioManager { DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN); } /** * Whether the device manufacturer has overridden app's orientation to * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER} to force app to fullscreen * and app has not opted-out from the treatment */ boolean isOverrideToFullscreenEnabled(String pkgName, int userId) { Boolean appAllowsOrientationOverride = readComponentProperty(mContext.getPackageManager(), pkgName, PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE); return mIsUserMinAspectRatioAppDefaultFlagEnabled && hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, pkgName) && !FALSE.equals(appAllowsOrientationOverride) && isFullscreenCompatChangeEnabled(pkgName, userId); } @VisibleForTesting boolean isFullscreenCompatChangeEnabled(String pkgName, int userId) { return CompatChanges.isChangeEnabled( OVERRIDE_ANY_ORIENTATION_TO_USER, pkgName, UserHandle.of(userId)); } private boolean isCurrentSelectionFromManufacturerOverride(String pkgName, int userId, @PackageManager.UserMinAspectRatio int aspectRatio) { return aspectRatio == USER_MIN_ASPECT_RATIO_UNSET && isOverrideToFullscreenEnabled(pkgName, userId); } private boolean hasLauncherEntry(@NonNull ApplicationInfo app) { return !mContext.getSystemService(LauncherApps.class) .getActivityList(app.packageName, getUserHandleForUid(app.uid)) Loading Loading @@ -197,13 +265,13 @@ public class UserAspectRatioManager { boolean containsColon = aspectRatioString.contains(":"); 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: case USER_MIN_ASPECT_RATIO_FULLSCREEN: case USER_MIN_ASPECT_RATIO_UNSET: case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: case USER_MIN_ASPECT_RATIO_4_3: case USER_MIN_ASPECT_RATIO_16_9: case USER_MIN_ASPECT_RATIO_3_2: if (containsColon) { String[] aspectRatioDigits = aspectRatioString.split(":"); String accessibleString = getAccessibleOption(aspectRatioDigits[0], Loading @@ -215,10 +283,18 @@ public class UserAspectRatioManager { userMinAspectRatioMap.put(aspectRatioVal, aspectRatioString); } } if (!userMinAspectRatioMap.containsKey(PackageManager.USER_MIN_ASPECT_RATIO_UNSET)) { if (!userMinAspectRatioMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { throw new RuntimeException("config_userAspectRatioOverrideValues options must have" + " USER_MIN_ASPECT_RATIO_UNSET value"); } if (mIsUserMinAspectRatioAppDefaultFlagEnabled) { userMinAspectRatioMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, userMinAspectRatioMap.get(USER_MIN_ASPECT_RATIO_UNSET)); if (mUserAspectRatioA11yMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { mUserAspectRatioA11yMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, mUserAspectRatioA11yMap.get(USER_MIN_ASPECT_RATIO_UNSET)); } } return userMinAspectRatioMap; } Loading @@ -236,17 +312,17 @@ public class UserAspectRatioManager { } // Options are customized per device and if strings are set to @null, use default switch (aspectRatioVal) { case PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN: case USER_MIN_ASPECT_RATIO_FULLSCREEN: return mContext.getString(R.string.user_aspect_ratio_fullscreen); case PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: return mContext.getString(R.string.user_aspect_ratio_half_screen); case PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: return mContext.getString(R.string.user_aspect_ratio_device_size); case PackageManager.USER_MIN_ASPECT_RATIO_4_3: case USER_MIN_ASPECT_RATIO_4_3: return mContext.getString(R.string.user_aspect_ratio_4_3); case PackageManager.USER_MIN_ASPECT_RATIO_16_9: case USER_MIN_ASPECT_RATIO_16_9: return mContext.getString(R.string.user_aspect_ratio_16_9); case PackageManager.USER_MIN_ASPECT_RATIO_3_2: case 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); Loading
src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt +8 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.GET_ACTIVITIES import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET import android.os.Build import android.os.Bundle Loading Loading @@ -139,7 +140,9 @@ class UserAspectRatioAppListModel(private val context: Context) recordList: List<UserAspectRatioAppListItemModel> ): List<SpinnerOption> { val hasSuggested = recordList.any { it.suggested } val hasOverride = recordList.any { it.userOverride != USER_MIN_ASPECT_RATIO_UNSET } val hasOverride = recordList.any { userAspectRatioManager.isAppOverridden(it.app, it.userOverride) } val options = mutableListOf(SpinnerItem.All) // Add suggested filter first as default if (hasSuggested) options.add(0, SpinnerItem.Suggested) Loading Loading @@ -187,7 +190,9 @@ class UserAspectRatioAppListModel(private val context: Context) ): Flow<List<UserAspectRatioAppListItemModel>> = recordListFlow.filterItem( when (SpinnerItem.entries.getOrNull(option)) { SpinnerItem.Suggested -> ({ it.canDisplay && it.suggested }) SpinnerItem.Overridden -> ({ it.userOverride != USER_MIN_ASPECT_RATIO_UNSET }) SpinnerItem.Overridden -> ({ userAspectRatioManager.isAppOverridden(it.app, it.userOverride) }) else -> ({ it.canDisplay }) } ) Loading @@ -197,7 +202,7 @@ class UserAspectRatioAppListModel(private val context: Context) val summary by remember(record.userOverride) { flow { emit(userAspectRatioManager.getUserMinAspectRatioEntry(record.userOverride, record.app.packageName)) record.app.packageName, record.app.userId)) }.flowOn(Dispatchers.IO) }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder)) return { summary } Loading
tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java +70 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes
tests/spa_unit/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ <uses-permission android:name="android.permission.MANAGE_APPOPS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <application android:debuggable="true"> <provider android:name="com.android.settings.slices.SettingsSliceProvider" Loading