• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package com.android.settings.applications.specialaccess.interactacrossprofiles;
17 
18 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
19 import static android.content.pm.PackageManager.GET_ACTIVITIES;
20 
21 import android.annotation.Nullable;
22 import android.app.admin.DevicePolicyManager;
23 import android.app.settings.SettingsEnums;
24 import android.content.Context;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.CrossProfileApps;
27 import android.content.pm.PackageInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.UserInfo;
30 import android.os.Bundle;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.util.IconDrawableFactory;
34 import android.util.Pair;
35 import android.view.View;
36 
37 import androidx.preference.Preference;
38 import androidx.preference.Preference.OnPreferenceClickListener;
39 import androidx.preference.PreferenceScreen;
40 
41 import com.android.settings.R;
42 import com.android.settings.applications.AppInfoBase;
43 import com.android.settings.search.BaseSearchIndexProvider;
44 import com.android.settings.widget.EmptyTextSettings;
45 import com.android.settingslib.search.SearchIndexable;
46 import com.android.settingslib.widget.AppPreference;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 @SearchIndexable
52 public class InteractAcrossProfilesSettings extends EmptyTextSettings {
53     private Context mContext;
54     private PackageManager mPackageManager;
55     private UserManager mUserManager;
56     private CrossProfileApps mCrossProfileApps;
57     private IconDrawableFactory mIconDrawableFactory;
58 
59     @Override
onCreate(Bundle icicle)60     public void onCreate(Bundle icicle) {
61         super.onCreate(icicle);
62 
63         mContext = getContext();
64         mPackageManager = mContext.getPackageManager();
65         mUserManager = mContext.getSystemService(UserManager.class);
66         mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
67         mCrossProfileApps = mContext.getSystemService(CrossProfileApps.class);
68     }
69 
70     @Override
onResume()71     public void onResume() {
72         super.onResume();
73 
74         final PreferenceScreen screen = getPreferenceScreen();
75         screen.removeAll();
76 
77         replaceEnterprisePreferenceScreenTitle(CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
78                 R.string.interact_across_profiles_title);
79 
80         final ArrayList<Pair<ApplicationInfo, UserHandle>> crossProfileApps =
81                 collectConfigurableApps(mPackageManager, mUserManager, mCrossProfileApps);
82 
83         final Context prefContext = getPrefContext();
84         for (final Pair<ApplicationInfo, UserHandle> appData : crossProfileApps) {
85             final ApplicationInfo appInfo = appData.first;
86             final UserHandle user = appData.second;
87             final String packageName = appInfo.packageName;
88             final CharSequence label = appInfo.loadLabel(mPackageManager);
89 
90             final Preference pref = new AppPreference(prefContext);
91             pref.setIcon(mIconDrawableFactory.getBadgedIcon(appInfo, user.getIdentifier()));
92             pref.setTitle(mPackageManager.getUserBadgedLabel(label, user));
93             pref.setSummary(InteractAcrossProfilesDetails.getPreferenceSummary(
94                     prefContext, packageName));
95             pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
96                 @Override
97                 public boolean onPreferenceClick(Preference preference) {
98                     AppInfoBase.startAppInfoFragment(InteractAcrossProfilesDetails.class,
99                             mDevicePolicyManager.getResources().getString(
100                                     CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
101                                     () -> getString(R.string.interact_across_profiles_title)),
102                             packageName,
103                             appInfo.uid,
104                             InteractAcrossProfilesSettings.this/* source */,
105                             -1/* request */,
106                             getMetricsCategory());
107                     return true;
108                 }
109             });
110             screen.addPreference(pref);
111         }
112     }
113 
114     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)115     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
116         super.onViewCreated(view, savedInstanceState);
117         setEmptyText(R.string.interact_across_profiles_empty_text);
118     }
119 
120     @Override
getPreferenceScreenResId()121     protected int getPreferenceScreenResId() {
122         return R.xml.interact_across_profiles;
123     }
124 
125     @Override
getMetricsCategory()126     public int getMetricsCategory() {
127         return SettingsEnums.INTERACT_ACROSS_PROFILES;
128     }
129 
130     /**
131      * @return the list of applications for the personal profile in the calling user's profile group
132      * that can configure interact across profiles.
133      */
collectConfigurableApps( PackageManager packageManager, UserManager userManager, CrossProfileApps crossProfileApps)134     static ArrayList<Pair<ApplicationInfo, UserHandle>> collectConfigurableApps(
135             PackageManager packageManager, UserManager userManager,
136             CrossProfileApps crossProfileApps) {
137         final UserHandle workProfile = getWorkProfile(userManager);
138         if (workProfile == null) {
139             return new ArrayList<>();
140         }
141         final UserHandle personalProfile = userManager.getProfileParent(workProfile);
142         if (personalProfile == null) {
143             return new ArrayList<>();
144         }
145 
146         final ArrayList<Pair<ApplicationInfo, UserHandle>> apps = new ArrayList<>();
147         for (PackageInfo packageInfo : getAllInstalledPackages(
148                 packageManager, personalProfile, workProfile)) {
149             if (crossProfileApps.canUserAttemptToConfigureInteractAcrossProfiles(
150                     packageInfo.packageName)) {
151                 apps.add(new Pair<>(packageInfo.applicationInfo, personalProfile));
152             }
153         }
154         return apps;
155     }
156 
getAllInstalledPackages( PackageManager packageManager, UserHandle personalProfile, UserHandle workProfile)157     private static List<PackageInfo> getAllInstalledPackages(
158             PackageManager packageManager, UserHandle personalProfile, UserHandle workProfile) {
159         List<PackageInfo> personalPackages = packageManager.getInstalledPackagesAsUser(
160                 GET_ACTIVITIES, personalProfile.getIdentifier());
161         List<PackageInfo> workPackages = packageManager.getInstalledPackagesAsUser(
162                 GET_ACTIVITIES, workProfile.getIdentifier());
163         List<PackageInfo> allPackages = new ArrayList<>(personalPackages);
164         for (PackageInfo workPackage : workPackages) {
165             if (allPackages.stream().noneMatch(
166                     p -> workPackage.packageName.equals(p.packageName))) {
167                 allPackages.add(workPackage);
168             }
169         }
170         return allPackages;
171     }
172 
173     /**
174      * @return the number of applications that can interact across profiles.
175      */
getNumberOfEnabledApps( Context context, PackageManager packageManager, UserManager userManager, CrossProfileApps crossProfileApps)176     static int getNumberOfEnabledApps(
177             Context context, PackageManager packageManager, UserManager userManager,
178             CrossProfileApps crossProfileApps) {
179         UserHandle workProfile = getWorkProfile(userManager);
180         if (workProfile == null) {
181             return 0;
182         }
183         UserHandle personalProfile = userManager.getProfileParent(workProfile);
184         if (personalProfile == null) {
185             return 0;
186         }
187         final ArrayList<Pair<ApplicationInfo, UserHandle>> apps =
188                 collectConfigurableApps(packageManager, userManager, crossProfileApps);
189         apps.removeIf(
190                 app -> !InteractAcrossProfilesDetails.isInteractAcrossProfilesEnabled(
191                         context, app.first.packageName)
192                         || !crossProfileApps.canConfigureInteractAcrossProfiles(
193                                 app.first.packageName));
194         return apps.size();
195     }
196 
197     /**
198      * Returns the work profile in the profile group of the calling user.
199      * Returns null if not found.
200      */
201     @Nullable
getWorkProfile(UserManager userManager)202     static UserHandle getWorkProfile(UserManager userManager) {
203         for (UserInfo user : userManager.getProfiles(UserHandle.myUserId())) {
204             if (userManager.isManagedProfile(user.id)) {
205                 return user.getUserHandle();
206             }
207         }
208         return null;
209     }
210 
211     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
212             new BaseSearchIndexProvider(R.xml.interact_across_profiles);
213 }
214