Merge "[3/n] Add aspect ratio app info page" into udc-qpr-dev am: 386b02e906 am: e5e57a8d9e

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/23819685

Change-Id: I0a880774214c804f2c22fb7aa876c39349e71b62
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Graciela Putri
2023-07-28 19:32:46 +00:00
committed by Automerger Merge Worker
13 changed files with 735 additions and 22 deletions

View File

@@ -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);
}
}

View File

@@ -0,0 +1,217 @@
/*
* 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_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_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<SelectorWithWidgetPreference> 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_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_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_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;
}
}

View File

@@ -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;
@@ -91,6 +92,32 @@ public class UserAspectRatioManager {
aspectRatio, mContext.getString(R.string.user_aspect_ratio_app_default));
}
/**
* @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}
*/
public boolean containsAspectRatioOption(@PackageManager.UserMinAspectRatio int option) {
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);
}
/**
* Whether an app's aspect ratio can be overridden by user. Only apps with launcher entry
* will be overridable.
@@ -122,14 +149,17 @@ public class UserAspectRatioManager {
final Map<Integer, String> 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_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 +169,29 @@ 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_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);

View File

@@ -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,
)
}

View File

@@ -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<UserAspectRatioAppListItemModel>.AppItem() {
val app = record.app
AppListItem(
onClick = AppInfoSettingsProvider.navigator(app)
onClick = { navigateToAppAspectRatioSettings(context, app) }
)
}

View File

@@ -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)