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