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.APP_CAN_ACCESS_PERSONAL_DATA;
19 import static android.app.admin.DevicePolicyResources.Strings.Settings.APP_CAN_ACCESS_PERSONAL_PERMISSIONS;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA;
21 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
22 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_SUMMARY;
23 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_TITLE;
24 import static android.app.admin.DevicePolicyResources.Strings.Settings.HOW_TO_DISCONNECT_APPS;
25 import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT;
26 import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT;
27 import static android.app.admin.DevicePolicyResources.Strings.Settings.ONLY_CONNECT_TRUSTED_APPS;
28 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
29 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
30 import static android.provider.Settings.ACTION_MANAGE_CROSS_PROFILE_ACCESS;
31 import static android.provider.Settings.Global.CONNECTED_APPS_ALLOWED_PACKAGES;
32 import static android.provider.Settings.Global.CONNECTED_APPS_DISALLOWED_PACKAGES;
33 
34 import android.Manifest;
35 import android.annotation.UserIdInt;
36 import android.app.ActionBar;
37 import android.app.AppOpsManager;
38 import android.app.admin.DevicePolicyEventLogger;
39 import android.app.admin.DevicePolicyManager;
40 import android.app.admin.flags.Flags;
41 import android.app.settings.SettingsEnums;
42 import android.content.Context;
43 import android.content.DialogInterface;
44 import android.content.Intent;
45 import android.content.PermissionChecker;
46 import android.content.pm.CrossProfileApps;
47 import android.content.pm.PackageInfo;
48 import android.content.pm.PackageManager;
49 import android.graphics.ColorMatrix;
50 import android.graphics.ColorMatrixColorFilter;
51 import android.graphics.drawable.Drawable;
52 import android.os.Bundle;
53 import android.os.UserHandle;
54 import android.os.UserManager;
55 import android.provider.Settings;
56 import android.stats.devicepolicy.DevicePolicyEnums;
57 import android.util.IconDrawableFactory;
58 import android.view.LayoutInflater;
59 import android.view.View;
60 import android.view.ViewGroup;
61 import android.widget.ImageView;
62 import android.widget.TextView;
63 
64 import androidx.appcompat.app.AlertDialog;
65 import androidx.preference.Preference;
66 
67 import com.android.settings.R;
68 import com.android.settings.applications.AppInfoBase;
69 import com.android.settings.applications.AppStoreUtil;
70 import com.android.settings.widget.CardPreference;
71 import com.android.settingslib.RestrictedLockUtils;
72 import com.android.settingslib.RestrictedSwitchPreference;
73 import com.android.settingslib.widget.LayoutPreference;
74 
75 import java.util.Collections;
76 import java.util.Optional;
77 import java.util.Set;
78 
79 public class InteractAcrossProfilesDetails extends AppInfoBase
80         implements Preference.OnPreferenceClickListener {
81 
82     private static final String INTERACT_ACROSS_PROFILES_SETTINGS_SWITCH =
83             "interact_across_profiles_settings_switch";
84     private static final String INTERACT_ACROSS_PROFILES_HEADER = "interact_across_profiles_header";
85     public static final String INSTALL_APP_BANNER_KEY = "install_app_banner";
86     public static final String INTERACT_ACROSS_PROFILE_EXTRA_SUMMARY_KEY =
87             "interact_across_profiles_extra_summary";
88     public static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
89     public static final String INTENT_KEY = "intent";
90     private static final String TAG = "InteractAcrossProfilesDetails";
91 
92     private Context mContext;
93     private CrossProfileApps mCrossProfileApps;
94     private UserManager mUserManager;
95     private RestrictedSwitchPreference mSwitchPref;
96     private LayoutPreference mHeader;
97     private CardPreference mInstallBanner;
98     private PackageManager mPackageManager;
99     private UserHandle mPersonalProfile;
100     private UserHandle mWorkProfile;
101     private boolean mInstalledInPersonal;
102     private boolean mInstalledInWork;
103     private String mAppLabel;
104     private Intent mInstallAppIntent;
105     private boolean mIsPageLaunchedByApp;
106 
107     @Override
onCreate(Bundle savedInstanceState)108     public void onCreate(Bundle savedInstanceState) {
109         super.onCreate(savedInstanceState);
110         mContext = getContext();
111         mCrossProfileApps = mContext.getSystemService(CrossProfileApps.class);
112         mUserManager = mContext.getSystemService(UserManager.class);
113         mPackageManager = mContext.getPackageManager();
114 
115         mWorkProfile = InteractAcrossProfilesSettings.getWorkProfile(mUserManager);
116         mPersonalProfile = mUserManager.getProfileParent(mWorkProfile);
117         mInstalledInWork = isPackageInstalled(mPackageName, mWorkProfile.getIdentifier());
118         mInstalledInPersonal = isPackageInstalled(mPackageName, mPersonalProfile.getIdentifier());
119 
120         mAppLabel = mPackageInfo.applicationInfo.loadLabel(mPackageManager).toString();
121         mInstallAppIntent = AppStoreUtil.getAppStoreLink(mContext, mPackageName);
122 
123         addPreferencesFromResource(R.xml.interact_across_profiles_permissions_details);
124     }
125 
126     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)127     public View onCreateView(LayoutInflater inflater, ViewGroup container,
128             Bundle savedInstanceState) {
129         final View view =  super.onCreateView(inflater, container, savedInstanceState);
130 
131         replaceEnterprisePreferenceScreenTitle(CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
132                 R.string.interact_across_profiles_title);
133         replaceEnterpriseStringSummary("interact_across_profiles_summary_1",
134                 CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA,
135                 R.string.interact_across_profiles_summary_1);
136         replaceEnterpriseStringSummary("interact_across_profiles_summary_2",
137                 ONLY_CONNECT_TRUSTED_APPS,
138                 R.string.interact_across_profiles_summary_2);
139         replaceEnterpriseStringSummary("interact_across_profiles_extra_summary",
140                 HOW_TO_DISCONNECT_APPS,
141                 R.string.interact_across_profiles_summary_3);
142 
143         mSwitchPref = findPreference(INTERACT_ACROSS_PROFILES_SETTINGS_SWITCH);
144         mSwitchPref.setOnPreferenceClickListener(this);
145 
146         mHeader = findPreference(INTERACT_ACROSS_PROFILES_HEADER);
147 
148         mInstallBanner = findPreference(INSTALL_APP_BANNER_KEY);
149         mInstallBanner.setOnPreferenceClickListener(this);
150 
151         mIsPageLaunchedByApp = launchedByApp();
152 
153         // refreshUi checks that the user can still configure the appOp, return to the
154         // previous page if it can't.
155         if (!refreshUi()) {
156             setIntentAndFinish(true/* appChanged */);
157         }
158         addAppTitleAndIcons(mPersonalProfile, mWorkProfile);
159         styleActionBar();
160         maybeShowExtraSummary();
161         logPageLaunchMetrics();
162 
163         return view;
164     }
165 
maybeShowExtraSummary()166     private void maybeShowExtraSummary() {
167         Preference extraSummary = findPreference(INTERACT_ACROSS_PROFILE_EXTRA_SUMMARY_KEY);
168         if (extraSummary == null) {
169             return;
170         }
171         extraSummary.setVisible(mIsPageLaunchedByApp);
172     }
173 
logPageLaunchMetrics()174     private void logPageLaunchMetrics() {
175         if (!mCrossProfileApps.canConfigureInteractAcrossProfiles(mPackageName)) {
176             logNonConfigurableAppMetrics();
177         }
178         if (mIsPageLaunchedByApp) {
179             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_APP);
180         } else {
181             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_SETTINGS);
182         }
183     }
184 
logNonConfigurableAppMetrics()185     private void logNonConfigurableAppMetrics() {
186         if (!isCrossProfilePackageAllowlisted(mPackageName)) {
187             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_ADMIN_RESTRICTED);
188             return;
189         }
190         if (mInstallBanner == null) {
191             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_MISSING_INSTALL_BANNER_INTENT);
192         }
193         if (!mInstalledInPersonal) {
194             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_MISSING_PERSONAL_APP);
195             return;
196         }
197         if (!mInstalledInWork) {
198             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_MISSING_WORK_APP);
199         }
200     }
201 
logEvent(int eventId)202     private void logEvent(int eventId) {
203         DevicePolicyEventLogger.createEvent(eventId)
204                 .setStrings(mPackageName)
205                 .setInt(UserHandle.myUserId())
206                 .setAdmin(RestrictedLockUtils.getProfileOrDeviceOwner(
207                         mContext, mWorkProfile).component)
208                 .write();
209     }
210 
addAppTitleAndIcons(UserHandle personalProfile, UserHandle workProfile)211     private void addAppTitleAndIcons(UserHandle personalProfile, UserHandle workProfile) {
212         final TextView title = mHeader.findViewById(R.id.entity_header_title);
213         if (title != null) {
214             final String appLabel = mPackageInfo.applicationInfo.loadLabel(
215                     mPackageManager).toString();
216             title.setText(appLabel);
217         }
218 
219         final ImageView personalIconView = mHeader.findViewById(
220                 com.android.settingslib.widget.preference.layout.R.id.entity_header_icon_personal);
221         if (personalIconView != null) {
222             Drawable icon = IconDrawableFactory.newInstance(mContext)
223                     .getBadgedIcon(mPackageInfo.applicationInfo, personalProfile.getIdentifier())
224                     .mutate();
225             if (!mInstalledInPersonal) {
226                 icon.setColorFilter(createSuspendedColorMatrix());
227             }
228             personalIconView.setImageDrawable(icon);
229         }
230 
231         final ImageView workIconView = mHeader.findViewById(
232                 com.android.settingslib.widget.preference.layout.R.id.entity_header_icon_work);
233         if (workIconView != null) {
234             Drawable icon = IconDrawableFactory.newInstance(mContext)
235                     .getBadgedIcon(mPackageInfo.applicationInfo, workProfile.getIdentifier())
236                     .mutate();
237             if (!mInstalledInWork) {
238                 icon.setColorFilter(createSuspendedColorMatrix());
239             }
240             workIconView.setImageDrawable(icon);
241         }
242     }
243 
styleActionBar()244     private void styleActionBar() {
245         final ActionBar actionBar = getActivity().getActionBar();
246         if (actionBar != null) {
247             actionBar.setElevation(0);
248         }
249     }
250 
createSuspendedColorMatrix()251     private ColorMatrixColorFilter createSuspendedColorMatrix() {
252         int grayValue = 127;
253         float scale = 0.5f; // half bright
254 
255         ColorMatrix tempBrightnessMatrix = new ColorMatrix();
256         float[] mat = tempBrightnessMatrix.getArray();
257         mat[0] = scale;
258         mat[6] = scale;
259         mat[12] = scale;
260         mat[4] = grayValue;
261         mat[9] = grayValue;
262         mat[14] = grayValue;
263 
264         ColorMatrix matrix = new ColorMatrix();
265         matrix.setSaturation(0.0f);
266         matrix.preConcat(tempBrightnessMatrix);
267         return new ColorMatrixColorFilter(matrix);
268     }
269 
270     @Override
onPreferenceClick(Preference preference)271     public boolean onPreferenceClick(Preference preference) {
272         // refreshUi checks that the user can still configure the appOp, return to the
273         // previous page if it can't.
274         if (!refreshUi()) {
275             setIntentAndFinish(true/* appChanged */);
276         }
277         if (preference == mSwitchPref) {
278             handleSwitchPreferenceClick();
279             return true;
280         }
281         if (preference == mInstallBanner) {
282             handleInstallBannerClick();
283             return true;
284         }
285         return false;
286     }
287 
handleSwitchPreferenceClick()288     private void handleSwitchPreferenceClick() {
289         if (isInteractAcrossProfilesEnabled()) {
290             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_PERMISSION_REVOKED);
291             enableInteractAcrossProfiles(false);
292             refreshUi();
293         } else {
294             showConsentDialog();
295         }
296     }
297 
showConsentDialog()298     private void showConsentDialog() {
299         final View dialogView = getLayoutInflater().inflate(
300                 R.layout.interact_across_profiles_consent_dialog, null);
301 
302         final TextView dialogTitle = dialogView.findViewById(
303                 R.id.interact_across_profiles_consent_dialog_title);
304         dialogTitle.setText(mDpm.getResources().getString(CONNECT_APPS_DIALOG_TITLE, () ->
305                 getString(R.string.interact_across_profiles_consent_dialog_title, mAppLabel),
306                 mAppLabel));
307 
308         final TextView appDataSummary = dialogView.findViewById(R.id.app_data_summary);
309         appDataSummary.setText(
310                 mDpm.getResources().getString(APP_CAN_ACCESS_PERSONAL_DATA,
311                         () -> getString(
312                                 R.string.interact_across_profiles_consent_dialog_app_data_summary,
313                                 mAppLabel), mAppLabel));
314 
315         final TextView permissionsSummary = dialogView.findViewById(R.id.permissions_summary);
316         permissionsSummary.setText(mDpm.getResources().getString(
317                 APP_CAN_ACCESS_PERSONAL_PERMISSIONS,
318                 () -> getString(
319                         R.string.interact_across_profiles_consent_dialog_permissions_summary,
320                         mAppLabel),
321                 mAppLabel));
322 
323         final TextView dialogSummary =
324                 dialogView.findViewById(R.id.interact_across_profiles_consent_dialog_summary);
325         dialogSummary.setText(mDpm.getResources().getString(CONNECT_APPS_DIALOG_SUMMARY,
326                 () -> getString(
327                         R.string.interact_across_profiles_consent_dialog_summary)));
328 
329         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
330         builder.setView(dialogView)
331                 .setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() {
332                     public void onClick(DialogInterface dialog, int which) {
333                         logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_USER_CONSENTED);
334                         enableInteractAcrossProfiles(true);
335                         refreshUi();
336                         if (mIsPageLaunchedByApp) {
337                             setIntentAndFinish(/* appChanged= */ true);
338                         }
339                     }
340                 })
341                 .setNegativeButton(R.string.deny, new DialogInterface.OnClickListener() {
342                     public void onClick(DialogInterface dialog, int which) {
343                         logEvent(
344                                 DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_USER_DECLINED_CONSENT);
345                         refreshUi();
346                     }
347                 })
348                 .create().show();
349     }
350 
isInteractAcrossProfilesEnabled()351     private boolean isInteractAcrossProfilesEnabled() {
352         return isInteractAcrossProfilesEnabled(mContext, mPackageName);
353     }
354 
isInteractAcrossProfilesEnabled( Context context, String packageName)355     static boolean isInteractAcrossProfilesEnabled(
356             Context context, String packageName) {
357         UserManager userManager = context.getSystemService(UserManager.class);
358         UserHandle workProfile = InteractAcrossProfilesSettings.getWorkProfile(userManager);
359         if (workProfile == null) {
360             return false;
361         }
362         UserHandle personalProfile = userManager.getProfileParent(workProfile);
363         return context.getSystemService(
364                 CrossProfileApps.class).canConfigureInteractAcrossProfiles(packageName)
365                 && isInteractAcrossProfilesEnabledInProfile(context, packageName, personalProfile)
366                 && isInteractAcrossProfilesEnabledInProfile(context, packageName, workProfile);
367 
368     }
369 
isInteractAcrossProfilesEnabledInProfile( Context context, String packageName, UserHandle userHandle)370     private static boolean isInteractAcrossProfilesEnabledInProfile(
371             Context context, String packageName, UserHandle userHandle) {
372         final PackageManager packageManager = context.getPackageManager();
373         final int uid;
374         try {
375             uid = packageManager.getApplicationInfoAsUser(
376                     packageName, /* flags= */0, userHandle).uid;
377         } catch (PackageManager.NameNotFoundException e) {
378             return false;
379         }
380         return PermissionChecker.PERMISSION_GRANTED
381                 == PermissionChecker.checkPermissionForPreflight(
382                 context,
383                 Manifest.permission.INTERACT_ACROSS_PROFILES,
384                 PermissionChecker.PID_UNKNOWN,
385                 uid,
386                 packageName);
387     }
388 
enableInteractAcrossProfiles(boolean newState)389     private void enableInteractAcrossProfiles(boolean newState) {
390         mCrossProfileApps.setInteractAcrossProfilesAppOp(
391                 mPackageName, newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
392         setUserPreferenceForPackage(newState, mPackageName);
393     }
394 
handleInstallBannerClick()395     private void handleInstallBannerClick() {
396         if (mInstallAppIntent != null
397                 && !mInstalledInWork
398                 && isInstallableInProfile(mInstallAppIntent, mWorkProfile)) {
399             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_CLICKED);
400             mContext.startActivityAsUser(mInstallAppIntent, mWorkProfile);
401             return;
402         }
403         if (mInstallAppIntent != null
404                 && !mInstalledInPersonal
405                 && isInstallableInProfile(mInstallAppIntent, mPersonalProfile)) {
406             logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_CLICKED);
407             mContext.startActivityAsUser(mInstallAppIntent, mPersonalProfile);
408             return;
409         }
410         logEvent(DevicePolicyEnums.CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_NO_INTENT_CLICKED);
411     }
412 
413     /**
414      * @return the summary for the current state of whether the app associated with the given
415      * {@code packageName} is allowed to interact across profiles.
416      */
getPreferenceSummary(Context context, String packageName)417     public static String getPreferenceSummary(Context context, String packageName) {
418         return context.getString(isInteractAcrossProfilesEnabled(context, packageName)
419                 ? R.string.interact_across_profiles_summary_allowed
420                 : R.string.interact_across_profiles_summary_not_allowed);
421     }
422 
423     @Override
refreshUi()424     protected boolean refreshUi() {
425         if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
426             return false;
427         }
428         if (!mCrossProfileApps.canUserAttemptToConfigureInteractAcrossProfiles(mPackageName)) {
429             // Invalid app entry. Should not allow changing permission
430             mSwitchPref.setEnabled(false);
431             return false;
432         }
433         if (!mCrossProfileApps.canConfigureInteractAcrossProfiles(mPackageName)) {
434             return refreshUiForNonConfigurableApps();
435         }
436         refreshUiForConfigurableApps();
437         return true;
438     }
439 
refreshUiForNonConfigurableApps()440     private boolean refreshUiForNonConfigurableApps() {
441         mSwitchPref.setChecked(false);
442         mSwitchPref.setTitle(R.string.interact_across_profiles_switch_disabled);
443         if (!isCrossProfilePackageAllowlisted(mPackageName)) {
444             mInstallBanner.setVisible(false);
445             mSwitchPref.setDisabledByAdmin(RestrictedLockUtils.getProfileOrDeviceOwner(
446                     mContext, mWorkProfile));
447             return true;
448         }
449         mSwitchPref.setEnabled(false);
450         if (!mInstalledInPersonal && !mInstalledInWork) {
451             return false;
452         }
453         if (!mInstalledInPersonal) {
454             mInstallBanner.setTitle(
455                     mDpm.getResources().getString(INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT,
456                             () -> getString(
457                                     R.string.interact_across_profiles_install_personal_app_title,
458                                     mAppLabel),
459                             mAppLabel));
460             if (mInstallAppIntent != null
461                     && isInstallableInProfile(mInstallAppIntent, mPersonalProfile)) {
462                 mInstallBanner.setSummary(
463                         R.string.interact_across_profiles_install_app_summary);
464             }
465             mInstallBanner.setVisible(true);
466             return true;
467         }
468         if (!mInstalledInWork) {
469             mInstallBanner.setTitle(
470                     mDpm.getResources().getString(INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT,
471                             () -> getString(
472                                     R.string.interact_across_profiles_install_work_app_title,
473                                     mAppLabel),
474                             mAppLabel));
475             if (mInstallAppIntent != null
476                     && isInstallableInProfile(mInstallAppIntent, mWorkProfile)) {
477                 mInstallBanner.setSummary(
478                         R.string.interact_across_profiles_install_app_summary);
479             }
480             mInstallBanner.setVisible(true);
481             return true;
482         }
483         return false;
484     }
485 
isCrossProfilePackageAllowlisted(String packageName)486     private boolean isCrossProfilePackageAllowlisted(String packageName) {
487         return mContext.getSystemService(DevicePolicyManager.class)
488                 .getAllCrossProfilePackages().contains(packageName);
489     }
490 
isPackageInstalled(String packageName, @UserIdInt int userId)491     private boolean isPackageInstalled(String packageName, @UserIdInt int userId) {
492         final PackageInfo info;
493         try {
494             info = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */0)
495                     .getPackageManager().getPackageInfo(packageName,
496                             MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
497         } catch (PackageManager.NameNotFoundException e) {
498             return false;
499         }
500         return info != null;
501     }
502 
isInstallableInProfile(Intent intent, UserHandle profile)503     private boolean isInstallableInProfile(Intent intent, UserHandle profile) {
504         return !mContext.getPackageManager()
505                 .queryIntentActivitiesAsUser(intent, /* flags= */ 0, profile)
506                 .isEmpty();
507     }
508 
refreshUiForConfigurableApps()509     private void refreshUiForConfigurableApps() {
510         mInstallBanner.setVisible(false);
511         mSwitchPref.setEnabled(true);
512         if (isInteractAcrossProfilesEnabled()) {
513             enableSwitchPref();
514         } else {
515             disableSwitchPref();
516         }
517     }
518 
enableSwitchPref()519     private void enableSwitchPref() {
520         mSwitchPref.setChecked(true);
521         mSwitchPref.setTitle(R.string.interact_across_profiles_switch_enabled);
522         final ImageView horizontalArrowIcon =
523                 mHeader.findViewById(com.android.settingslib.widget.preference.layout.R.id.entity_header_swap_horiz);
524         if (horizontalArrowIcon != null) {
525             horizontalArrowIcon.setImageDrawable(
526                     mContext.getDrawable(
527                             com.android.settingslib.widget.preference.layout.R.drawable.ic_swap_horiz_blue));
528         }
529     }
530 
disableSwitchPref()531     private void disableSwitchPref() {
532         mSwitchPref.setChecked(false);
533         mSwitchPref.setTitle(R.string.interact_across_profiles_switch_disabled);
534         final ImageView horizontalArrowIcon =
535                 mHeader.findViewById(com.android.settingslib.widget.preference.layout.R.id.entity_header_swap_horiz);
536         if (horizontalArrowIcon != null) {
537             horizontalArrowIcon.setImageDrawable(
538                     mContext.getDrawable(
539                             com.android.settingslib.widget.preference.layout.R.drawable.ic_swap_horiz_grey));
540         }
541     }
542 
543     @Override
createDialog(int id, int errorCode)544     protected AlertDialog createDialog(int id, int errorCode) {
545         return null;
546     }
547 
548     @Override
getMetricsCategory()549     public int getMetricsCategory() {
550         return SettingsEnums.INTERACT_ACROSS_PROFILES;
551     }
552 
launchedByApp()553     private boolean launchedByApp() {
554         final Bundle bundle = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGS);
555         if (bundle == null) {
556             return false;
557         }
558         final Intent intent = (Intent) bundle.get(INTENT_KEY);
559         if (intent == null) {
560             return false;
561         }
562         return ACTION_MANAGE_CROSS_PROFILE_ACCESS.equals(intent.getAction());
563     }
564 
setUserPreferenceForPackage(boolean enabled, String crossProfilePackage)565     private void setUserPreferenceForPackage(boolean enabled, String crossProfilePackage) {
566         if (!Flags.backupConnectedAppsSettings()) {
567             return;
568         }
569         String allowedPackagesString = Settings.Global.getString(getContentResolver(),
570                 CONNECTED_APPS_ALLOWED_PACKAGES);
571         String disallowedPackagesString = Settings.Global.getString(getContentResolver(),
572                 CONNECTED_APPS_DISALLOWED_PACKAGES);
573 
574         Set<String> allowedPackagesSet = getSetFromString(allowedPackagesString);
575         Set<String> disallowedPackagesSet = getSetFromString(disallowedPackagesString);
576 
577         if (enabled) {
578             allowedPackagesSet.add(crossProfilePackage);
579             disallowedPackagesSet.remove(crossProfilePackage);
580 
581         } else {
582             allowedPackagesSet.remove(crossProfilePackage);
583             disallowedPackagesSet.add(crossProfilePackage);
584         }
585 
586         Settings.Global.putString(getContentResolver(),
587                 CONNECTED_APPS_ALLOWED_PACKAGES,
588                 String.join(",", allowedPackagesSet));
589 
590         Settings.Global.putString(getContentResolver(),
591                 CONNECTED_APPS_DISALLOWED_PACKAGES,
592                 String.join(",", disallowedPackagesSet));
593     }
594 
getSetFromString(String packages)595     private Set<String> getSetFromString(String packages) {
596         return Optional.ofNullable(packages)
597                 .map(pkg -> Set.of(pkg.split(",")))
598                 .orElse(Collections.emptySet());
599     }
600 }
601