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.privacy;
18 
19 import static com.android.car.ui.preference.CarUiTwoActionTextPreference.SECONDARY_ACTION_STYLE_BORDERLESS;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.PackageManager.NameNotFoundException;
27 import android.content.pm.PackageManager.PackageInfoFlags;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.UserHandle;
31 import android.util.IconDrawableFactory;
32 
33 import androidx.annotation.Nullable;
34 
35 import com.android.car.settings.R;
36 import com.android.car.settings.common.Logger;
37 import com.android.car.ui.preference.CarUiPreference;
38 import com.android.car.ui.preference.CarUiTwoActionTextPreference;
39 
40 /** Utilities related to preferences with required and infotainment apps. */
41 public final class RequiredInfotainmentAppsUtils {
42     private static final Logger LOG = new Logger(RequiredInfotainmentAppsUtils.class);
43     private static final String PRIVACY_POLICY_KEY = "privacy_policy";
44 
RequiredInfotainmentAppsUtils()45     private RequiredInfotainmentAppsUtils() {}
46 
47     /**
48      * Creates a {@link CarUiTwoActionTextPreference} for a required app with its privacy policy and
49      * a link to its permission settings.
50      */
51     @Nullable
createRequiredAppPreference( Context context, PackageManager packageManager, String pkgName, UserHandle userHandle, String permissionGroup, boolean showSummary)52     public static CarUiTwoActionTextPreference createRequiredAppPreference(
53             Context context, PackageManager packageManager, String pkgName, UserHandle userHandle,
54             String permissionGroup, boolean showSummary) {
55         ApplicationInfo appInfo = getApplicationInfo(packageManager, pkgName, userHandle);
56         if (appInfo == null || !appInfo.enabled) {
57             return null;
58         }
59 
60         CarUiTwoActionTextPreference pref =
61                 new CarUiTwoActionTextPreference(context, SECONDARY_ACTION_STYLE_BORDERLESS);
62         setAppPreference(context, packageManager, pkgName, userHandle, permissionGroup, showSummary,
63                 pref, appInfo);
64 
65         pref.setSecondaryActionText(R.string.required_apps_privacy_policy_button_text);
66 
67         Bundle bundle = appInfo.metaData;
68         if (bundle == null) {
69             LOG.e(pkgName + "doesn't provide meta data in manifest");
70             return pref;
71         }
72 
73         CharSequence privacyPolicyLink = bundle.getCharSequence(PRIVACY_POLICY_KEY);
74         if (privacyPolicyLink == null) {
75             LOG.e(pkgName + " doesn't provide privacy policy");
76             return pref;
77         }
78 
79         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(privacyPolicyLink.toString()));
80         pref.setOnSecondaryActionClickListener(
81                 () -> {
82                     context.startActivity(intent);
83                 });
84         return pref;
85     }
86 
87     /**
88      * Creates a {@link CarUiPreference} for an infotainment app.
89      */
90     @Nullable
createInfotainmentAppPreference( Context context, PackageManager packageManager, String pkgName, UserHandle userHandle, String permissionGroup, boolean showSummary)91     public static CarUiPreference createInfotainmentAppPreference(
92             Context context, PackageManager packageManager, String pkgName, UserHandle userHandle,
93             String permissionGroup, boolean showSummary) {
94         ApplicationInfo appInfo = getApplicationInfo(packageManager, pkgName, userHandle);
95         if (appInfo == null || !appInfo.enabled) {
96             return null;
97         }
98 
99         CarUiPreference pref = new CarUiPreference(context);
100         setAppPreference(context, packageManager, pkgName, userHandle, permissionGroup, showSummary,
101                 pref, appInfo);
102         return pref;
103     }
104 
getApplicationInfo( PackageManager packageManager, String pkgName, UserHandle userHandle)105     private static ApplicationInfo getApplicationInfo(
106             PackageManager packageManager, String pkgName, UserHandle userHandle) {
107         ApplicationInfo appInfo = null;
108         try {
109             appInfo = packageManager.getApplicationInfoAsUser(
110                     pkgName, PackageManager.GET_META_DATA, userHandle.getIdentifier());
111         } catch (NameNotFoundException ex) {
112             LOG.e("Failed to get application info for " + pkgName);
113         }
114         return appInfo;
115     }
116 
setAppPreference( Context context, PackageManager packageManager, String pkgName, UserHandle userHandle, String permissionGroup, boolean showSummary, CarUiPreference pref, ApplicationInfo appInfo)117     private static void setAppPreference(
118             Context context, PackageManager packageManager, String pkgName, UserHandle userHandle,
119             String permissionGroup, boolean showSummary, CarUiPreference pref,
120             ApplicationInfo appInfo) {
121         IconDrawableFactory drawableFactory = IconDrawableFactory.newInstance(context);
122         pref.setIcon(drawableFactory.getBadgedIcon(appInfo, userHandle.getIdentifier()));
123 
124         CharSequence appLabel = packageManager.getApplicationLabel(appInfo);
125         CharSequence badgedAppLabel = packageManager.getUserBadgedLabel(appLabel, userHandle);
126         pref.setTitle(badgedAppLabel);
127 
128         pref.setOnPreferenceClickListener(
129                 preference -> {
130                     Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
131                     intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroup);
132                     intent.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
133                     intent.putExtra(Intent.EXTRA_USER, userHandle);
134                     context.startActivity(intent);
135                     return true;
136                 });
137 
138         if (showSummary) {
139             PackageInfo packageInfo;
140             try {
141                 packageInfo = packageManager.getPackageInfo(pkgName,
142                         PackageInfoFlags.of(PackageManager.GET_PERMISSIONS));
143             } catch (NameNotFoundException ex) {
144                 LOG.e("Failed to get package info for " + pkgName);
145                 return;
146             }
147             int permGroupGrantStatus = PermissionUtils.getPermissionGroupGrantStatus(
148                     context, packageInfo, permissionGroup, userHandle);
149             pref.setSummary(permGroupGrantStatus);
150         }
151     }
152 }
153