[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