• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.applications.appinfo;
18 
19 import static android.os.UserHandle.getUserHandleForUid;
20 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
21 
22 import android.app.ActivityManager;
23 import android.app.AppGlobals;
24 import android.content.Context;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.IPackageManager;
27 import android.content.pm.LauncherApps;
28 import android.content.pm.PackageManager;
29 import android.os.RemoteException;
30 import android.provider.DeviceConfig;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.Nullable;
34 
35 import com.android.car.settings.common.Logger;
36 
37 /**
38  * Manager for handling app aspect ratio override behavior
39  */
40 public final class AspectRatioManager {
41     private static final Logger LOG = new Logger(AspectRatioManager.class);
42     private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true;
43     private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
44             "enable_app_compat_aspect_ratio_user_settings";
45 
46     private final Context mContext;
47     private final IPackageManager mIPm;
48     private final ActivityManager mActivityManager;
49 
AspectRatioManager(Context context)50     public AspectRatioManager(Context context) {
51         mContext = context;
52         mIPm = AppGlobals.getPackageManager();
53         mActivityManager = mContext.getSystemService(ActivityManager.class);
54     }
55 
56     /** Determines whether an app should have aspect ratio settings */
shouldShowAspectRatioSettingsForApp(ApplicationInfo appInfo)57     public boolean shouldShowAspectRatioSettingsForApp(ApplicationInfo appInfo) {
58         if (appInfo == null) {
59             return false;
60         }
61 
62         return isFeatureEnabled() && canDisplayAspectRatioUi(appInfo);
63     }
64 
65     /**
66      * @return {@link PackageManager.UserMinAspectRatio} override for an app
67      */
68     @PackageManager.UserMinAspectRatio
getUserMinAspectRatioValue(@onNull String packageName, int uid)69     public int getUserMinAspectRatioValue(@NonNull String packageName, int uid)
70             throws RemoteException {
71         int aspectRatio = mIPm.getUserMinAspectRatio(packageName, uid);
72         return aspectRatio;
73     }
74 
75     /**
76      * Sets user-specified {@link PackageManager.UserMinAspectRatio} override for an app
77      */
setUserMinAspectRatio(@onNull String packageName, int uid, @PackageManager.UserMinAspectRatio int aspectRatio)78     public void setUserMinAspectRatio(@NonNull String packageName, int uid,
79             @PackageManager.UserMinAspectRatio int aspectRatio) throws RemoteException {
80         mIPm.setUserMinAspectRatio(packageName, uid, aspectRatio);
81         stopApp(packageName);
82     }
83 
stopApp(@onNull String packageName)84     private void stopApp(@NonNull String packageName) {
85         mActivityManager.forceStopPackage(packageName);
86     }
87 
88     /**
89      * Whether user aspect ratio settings is enabled for device.
90      */
isFeatureEnabled()91     private boolean isFeatureEnabled() {
92         final boolean isBuildTimeFlagEnabled = mContext.getResources().getBoolean(
93                 com.android.internal.R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled);
94         return getValueFromDeviceConfig(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS,
95                 DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS) && isBuildTimeFlagEnabled;
96     }
97 
getValueFromDeviceConfig(String name, boolean defaultValue)98     private boolean getValueFromDeviceConfig(String name, boolean defaultValue) {
99         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, name, defaultValue);
100     }
101 
102     /**
103      * Whether an app's aspect ratio can be overridden by user. Only apps with launcher entry
104      * will be overridable.
105      */
canDisplayAspectRatioUi(@onNull ApplicationInfo appInfo)106     private boolean canDisplayAspectRatioUi(@NonNull ApplicationInfo appInfo) {
107         Boolean appAllowsUserAspectRatioOverride = readComponentProperty(
108                 mContext.getPackageManager(), appInfo.packageName,
109                 PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
110         return !(Boolean.FALSE.equals(appAllowsUserAspectRatioOverride))
111                 && hasLauncherEntry(appInfo);
112     }
113 
hasLauncherEntry(@onNull ApplicationInfo app)114     private boolean hasLauncherEntry(@NonNull ApplicationInfo app) {
115         LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
116         if (launcherApps == null) {
117             return false;
118         }
119 
120         return !launcherApps
121                 .getActivityList(app.packageName, getUserHandleForUid(app.uid))
122                 .isEmpty();
123     }
124 
125     @Nullable
readComponentProperty(PackageManager pm, String packageName, String propertyName)126     private static Boolean readComponentProperty(PackageManager pm, String packageName,
127             String propertyName) {
128         try {
129             return pm.getProperty(propertyName, packageName).getBoolean();
130         } catch (PackageManager.NameNotFoundException e) {
131             LOG.e("Error getting property " + propertyName + " for package: " + packageName + " "
132                     + e);
133         }
134         return null;
135     }
136 }
137