[2/n] Add aspect ratio app list page under apps
Apps > General > Screen Size
To enable feature:
adb shell device_config put window_manager enable_app_compat_user_aspect_ratio_settings true
adb shell am force-stop com.android.settings
Fix: 287448088
Test: Manual
atest AspectRatioAppsPageProviderTest
atest AspectRatioUtilsTest
All CUJs passed in go/settings-cujs
Change-Id: I4de6c3cbdbdfbc79ed839ec149fb633344dcd3a7
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 3efa18f..5249e5a 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -378,6 +378,8 @@
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
/** Activity to manage Cloned Apps page */
public static class ClonedAppsListActivity extends SettingsActivity { /* empty */ }
+ /** Activity to manage Aspect Ratio app list page */
+ public static class UserAspectRatioAppListActivity extends SettingsActivity { /* empty */ }
public static class NotificationReviewPermissionsActivity extends SettingsActivity { /* empty */ }
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ChannelNotificationSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java b/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java
new file mode 100644
index 0000000..6ec2528
--- /dev/null
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioAppsPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Preference controller for
+ * {@link com.android.settings.spa.app.appcompat.UserAspectRatioAppsPageProvider}
+ */
+public class UserAspectRatioAppsPreferenceController extends BasePreferenceController {
+
+ public UserAspectRatioAppsPreferenceController(@NonNull Context context,
+ @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return UserAspectRatioManager.isFeatureEnabled(mContext)
+ ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getResources().getString(R.string.screen_size_summary, Build.MODEL);
+ }
+}
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
new file mode 100644
index 0000000..35bd7a9
--- /dev/null
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
@@ -0,0 +1,146 @@
+/*
+ * 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 android.app.AppGlobals;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class for handling app aspect ratio override
+ * {@link PackageManager.UserMinAspectRatio} set by user
+ */
+public class UserAspectRatioManager {
+ private static final Intent LAUNCHER_ENTRY_INTENT =
+ new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
+
+ // TODO(b/288142656): Enable user aspect ratio settings by default
+ private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+ @VisibleForTesting
+ static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
+ "enable_app_compat_user_aspect_ratio_settings";
+
+ private final Context mContext;
+ private final IPackageManager mIPm;
+ /** Apps that have launcher entry defined in manifest */
+ private final List<ResolveInfo> mInfoHasLauncherEntryList;
+ private final Map<Integer, String> mUserAspectRatioMap;
+
+ public UserAspectRatioManager(@NonNull Context context) {
+ mContext = context;
+ mIPm = AppGlobals.getPackageManager();
+ mInfoHasLauncherEntryList = context.getPackageManager().queryIntentActivities(
+ UserAspectRatioManager.LAUNCHER_ENTRY_INTENT, PackageManager.GET_META_DATA);
+ mUserAspectRatioMap = getUserMinAspectRatioMapping();
+ }
+
+ /**
+ * Whether user aspect ratio settings is enabled for device.
+ */
+ public static boolean isFeatureEnabled(Context context) {
+ final boolean isBuildTimeFlagEnabled = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled);
+ return isBuildTimeFlagEnabled && getValueFromDeviceConfig();
+ }
+
+ /**
+ * @return user-specific {@link PackageManager.UserMinAspectRatio} override for an app
+ */
+ @PackageManager.UserMinAspectRatio
+ public int getUserMinAspectRatioValue(@NonNull String packageName, int uid)
+ throws RemoteException {
+ return mIPm.getUserMinAspectRatio(packageName, uid);
+ }
+
+ /**
+ * @return corresponding string for {@link PackageManager.UserMinAspectRatio} value
+ */
+ @NonNull
+ public String getUserMinAspectRatioEntry(@PackageManager.UserMinAspectRatio int aspectRatio) {
+ return mUserAspectRatioMap.getOrDefault(
+ aspectRatio, mContext.getString(R.string.user_aspect_ratio_app_default));
+ }
+
+ /**
+ * Whether an app's aspect ratio can be overridden by user. Only apps with launcher entry
+ * will be overridable.
+ */
+ public boolean canDisplayAspectRatioUi(@NonNull ApplicationInfo app) {
+ boolean hasLauncherEntry = mInfoHasLauncherEntryList.stream()
+ .anyMatch(info -> info.activityInfo.packageName.equals(app.packageName));
+ 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);
+ }
+
+ @NonNull
+ private Map<Integer, String> getUserMinAspectRatioMapping() {
+ final String[] userMinAspectRatioStrings = mContext.getResources().getStringArray(
+ R.array.config_userAspectRatioOverrideEntries);
+ final int[] userMinAspectRatioValues = mContext.getResources().getIntArray(
+ R.array.config_userAspectRatioOverrideValues);
+ if (userMinAspectRatioStrings.length != userMinAspectRatioValues.length) {
+ throw new RuntimeException(
+ "config_userAspectRatioOverride options cannot be different length");
+ }
+
+ final Map<Integer, String> userMinAspectRatioMap = new ArrayMap<>();
+ for (int i = 0; i < userMinAspectRatioValues.length; i++) {
+ final int aspectRatioVal = userMinAspectRatioValues[i];
+ switch (aspectRatioVal) {
+ // Only map known values of UserMinAspectRatio and ignore unknown entries
+ case PackageManager.USER_MIN_ASPECT_RATIO_UNSET:
+ case PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
+ 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]);
+ }
+ }
+ if (!userMinAspectRatioMap.containsKey(PackageManager.USER_MIN_ASPECT_RATIO_UNSET)) {
+ throw new RuntimeException("config_userAspectRatioOverrideValues options must have"
+ + " USER_MIN_ASPECT_RATIO_UNSET value");
+ }
+ return userMinAspectRatioMap;
+ }
+
+ @VisibleForTesting
+ void addInfoHasLauncherEntry(@NonNull ResolveInfo infoHasLauncherEntry) {
+ mInfoHasLauncherEntryList.add(infoHasLauncherEntry);
+ }
+}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 548ca55..d734a27 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -269,6 +269,7 @@
public static final int LIST_TYPE_CLONED_APPS = 17;
public static final int LIST_TYPE_NFC_TAG_APPS = 18;
public static final int LIST_TYPE_TURN_SCREEN_ON = 19;
+ public static final int LIST_TYPE_USER_ASPECT_RATIO_APPS = 20;
// List types that should show instant apps.
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index 6574f69..8313686 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -20,6 +20,7 @@
import android.util.FeatureFlagUtils
import com.android.settings.Settings.AlarmsAndRemindersActivity
import com.android.settings.Settings.AppBatteryUsageActivity
+import com.android.settings.Settings.UserAspectRatioAppListActivity
import com.android.settings.Settings.ChangeNfcTagAppsActivity
import com.android.settings.Settings.ChangeWifiStateActivity
import com.android.settings.Settings.ClonedAppsListActivity
@@ -40,6 +41,7 @@
import com.android.settings.applications.manageapplications.ManageApplications.LIST_MANAGE_EXTERNAL_STORAGE
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE
+import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_USER_ASPECT_RATIO_APPS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
@@ -57,6 +59,7 @@
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_WIFI_ACCESS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_WRITE_SETTINGS
import com.android.settings.spa.app.AllAppListPageProvider
+import com.android.settings.spa.app.appcompat.UserAspectRatioAppsPageProvider
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
@@ -92,6 +95,7 @@
ClonedAppsListActivity::class to LIST_TYPE_CLONED_APPS,
ChangeNfcTagAppsActivity::class to LIST_TYPE_NFC_TAG_APPS,
TurnScreenOnSettingsActivity::class to LIST_TYPE_TURN_SCREEN_ON,
+ UserAspectRatioAppListActivity::class to LIST_TYPE_USER_ASPECT_RATIO_APPS,
)
@JvmField
@@ -114,6 +118,7 @@
LIST_TYPE_APPS_LOCALE -> AppLanguagesPageProvider.name
LIST_TYPE_MAIN -> AllAppListPageProvider.name
LIST_TYPE_NFC_TAG_APPS -> NfcTagAppsSettingsProvider.getAppListRoute()
+ LIST_TYPE_USER_ASPECT_RATIO_APPS -> UserAspectRatioAppsPageProvider.name
else -> null
}
}
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index b506005..db88784 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -20,6 +20,7 @@
import android.util.FeatureFlagUtils
import com.android.settings.spa.app.AllAppListPageProvider
import com.android.settings.spa.app.AppsMainPageProvider
+import com.android.settings.spa.app.appcompat.UserAspectRatioAppsPageProvider
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settings.spa.app.appinfo.CloneAppInfoSettingsProvider
import com.android.settings.spa.app.backgroundinstall.BackgroundInstalledAppsPageProvider
@@ -86,6 +87,7 @@
UsageStatsPageProvider,
PlatformCompatAppListPageProvider,
BackgroundInstalledAppsPageProvider,
+ UserAspectRatioAppsPageProvider,
CloneAppInfoSettingsProvider,
NetworkAndInternetPageProvider,
) + togglePermissionAppListTemplate.createPageProviders(),
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
new file mode 100644
index 0000000..34b6b66
--- /dev/null
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -0,0 +1,214 @@
+/*
+ * 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 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_UNSET
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+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.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
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.rememberContext
+import com.android.settingslib.spa.framework.compose.toState
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.util.asyncMap
+import com.android.settingslib.spa.framework.util.filterItem
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.ui.SettingsBody
+import com.android.settingslib.spa.widget.ui.SpinnerOption
+import com.android.settingslib.spaprivileged.model.app.AppListModel
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.userId
+import com.android.settingslib.spaprivileged.template.app.AppList
+import com.android.settingslib.spaprivileged.template.app.AppListInput
+import com.android.settingslib.spaprivileged.template.app.AppListItem
+import com.android.settingslib.spaprivileged.template.app.AppListItemModel
+import com.android.settingslib.spaprivileged.template.app.AppListPage
+import com.google.common.annotations.VisibleForTesting
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
+
+object UserAspectRatioAppsPageProvider : SettingsPageProvider {
+ override val name = "UserAspectRatioAppsPage"
+ private val owner = createSettingsPage()
+
+ override fun isEnabled(arguments: Bundle?): Boolean =
+ UserAspectRatioManager.isFeatureEnabled(SpaEnvironmentFactory.instance.appContext)
+
+ @Composable
+ override fun Page(arguments: Bundle?) =
+ UserAspectRatioAppList()
+
+ @Composable
+ @VisibleForTesting
+ fun EntryItem() =
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.screen_size_title)
+ override val summary = getSummary().toState()
+ override val onClick = navigator(name)
+ })
+
+ @VisibleForTesting
+ fun buildInjectEntry() = SettingsEntryBuilder
+ .createInject(owner)
+ .setSearchDataFn { null }
+ .setUiLayoutFn { EntryItem() }
+
+ @Composable
+ @VisibleForTesting
+ fun getSummary(): String = stringResource(R.string.screen_size_summary, Build.MODEL)
+}
+
+@Composable
+fun UserAspectRatioAppList(
+ appList: @Composable AppListInput<UserAspectRatioAppListItemModel>.() -> Unit
+ = { AppList() },
+) {
+ AppListPage(
+ title = stringResource(R.string.screen_size_title),
+ listModel = rememberContext(::UserAspectRatioAppListModel),
+ appList = appList,
+ header = {
+ Box(Modifier.padding(SettingsDimension.itemPadding)) {
+ SettingsBody(UserAspectRatioAppsPageProvider.getSummary())
+ }
+ }
+ )
+}
+
+data class UserAspectRatioAppListItemModel(
+ override val app: ApplicationInfo,
+ val override: Int,
+ val suggested: Boolean,
+ val canDisplay: Boolean,
+) : AppRecord
+
+class UserAspectRatioAppListModel(private val context: Context)
+ : AppListModel<UserAspectRatioAppListItemModel> {
+
+ private val packageManager = context.packageManager
+ private val userAspectRatioManager = UserAspectRatioManager(context)
+
+ override fun getSpinnerOptions(
+ recordList: List<UserAspectRatioAppListItemModel>
+ ): List<SpinnerOption> {
+ val hasSuggested = recordList.any { it.suggested }
+ val hasOverride = recordList.any { it.override != USER_MIN_ASPECT_RATIO_UNSET }
+ val options = mutableListOf(SpinnerItem.All)
+ // Add suggested filter first as default
+ if (hasSuggested) options.add(0, SpinnerItem.Suggested)
+ if (hasOverride) options += SpinnerItem.Overridden
+ return options.map {
+ SpinnerOption(
+ id = it.ordinal,
+ text = context.getString(it.stringResId),
+ )
+ }
+ }
+
+ @Composable
+ override fun AppListItemModel<UserAspectRatioAppListItemModel>.AppItem() {
+ val app = record.app
+ AppListItem(
+ onClick = AppInfoSettingsProvider.navigator(app)
+ )
+ }
+
+ override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
+ userIdFlow.combine(appListFlow) { uid, appList ->
+ appList.asyncMap { app ->
+ UserAspectRatioAppListItemModel(
+ app = app,
+ suggested = !app.isSystemApp && getPackageAndActivityInfo(
+ app)?.isFixedOrientationOrAspectRatio() == true,
+ override = userAspectRatioManager.getUserMinAspectRatioValue(
+ app.packageName, uid),
+ canDisplay = userAspectRatioManager.canDisplayAspectRatioUi(app),
+ )
+ }
+ }
+
+ override fun filter(
+ userIdFlow: Flow<Int>,
+ option: Int,
+ recordListFlow: Flow<List<UserAspectRatioAppListItemModel>>
+ ): Flow<List<UserAspectRatioAppListItemModel>> = recordListFlow.filterItem(
+ when (SpinnerItem.values().getOrNull(option)) {
+ SpinnerItem.Suggested -> ({ it.canDisplay && it.suggested })
+ SpinnerItem.Overridden -> ({ it.override != USER_MIN_ASPECT_RATIO_UNSET })
+ else -> ({ it.canDisplay })
+ }
+ )
+
+ @OptIn(ExperimentalLifecycleComposeApi::class)
+ @Composable
+ override fun getSummary(option: Int, record: UserAspectRatioAppListItemModel) : State<String> =
+ remember(record.override) {
+ flow {
+ emit(userAspectRatioManager.getUserMinAspectRatioEntry(record.override))
+ }.flowOn(Dispatchers.IO)
+ }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder))
+
+ private fun getPackageAndActivityInfo(app: ApplicationInfo): PackageInfo? = try {
+ packageManager.getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
+ } catch (e: Exception) {
+ // Query PackageManager.getPackageInfoAsUser() with GET_ACTIVITIES_FLAGS could cause
+ // exception sometimes. Since we reply on this flag to retrieve the Picture In Picture
+ // packages, we need to catch the exception to alleviate the impact before PackageManager
+ // fixing this issue or provide a better api.
+ Log.e(TAG, "Exception while getPackageInfoAsUser", e)
+ null
+ }
+
+ companion object {
+ private const val TAG = "AspectRatioAppsListModel"
+ private fun PackageInfo.isFixedOrientationOrAspectRatio() =
+ activities?.any { a -> a.isFixedOrientation || a.hasFixedAspectRatio() } ?: false
+ private val GET_ACTIVITIES_FLAGS =
+ PackageManager.PackageInfoFlags.of(GET_ACTIVITIES.toLong())
+ }
+}
+
+private enum class SpinnerItem(val stringResId: Int) {
+ Suggested(R.string.user_aspect_ratio_suggested_apps_label),
+ All(R.string.filter_all_apps),
+ Overridden(R.string.user_aspect_ratio_overridden_apps_label)
+}
\ No newline at end of file