diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java index f4dc6ba5e2ded..71dec457cc2e2 100644 --- a/core/java/android/app/admin/DevicePolicyResources.java +++ b/core/java/android/app/admin/DevicePolicyResources.java @@ -1851,9 +1851,54 @@ public final class DevicePolicyResources { public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON = PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT"; + /** + * Information section shown on a dialog when the user is unable to place a call in + * the personal profile due to admin restrictions, and must choose whether to place + * the call from the work profile or cancel. + */ + public static final String MINIRESOLVER_WORK_TELEPHONY_CALL_BLOCKED_INFORMATION = + PREFIX + "MINIRESOLVER_WORK_TELEPHONY_INFORMATION"; + + /** + * Information section shown on a dialog when the user is unable to send a text in + * the personal profile due to admin restrictions, and must choose whether to place + * the call from the work profile or cancel. + */ + public static final String MINIRESOLVER_WORK_TELEPHONY_TEXT_BLOCKED_INFORMATION = + PREFIX + "MINIRESOLVER_WORK_TELEPHONY_INFORMATION"; + + + /** + * Button for a dialog shown when the user is unable to place a call in the personal + * profile due to admin restrictions, and must choose whether to place the call from + * the work profile or cancel. + */ + public static final String MINIRESOLVER_CALL_FROM_WORK = + PREFIX + "MINIRESOLVER_CALL_FROM_WORK"; + + /** + * Button for a dialog shown when the user has no apps capable of handling an intent + * in the personal profile, and must choose whether to open the intent in a + * cross-profile app in the work profile, or cancel. + */ + public static final String MINIRESOLVER_SWITCH_TO_WORK = + PREFIX + "MINIRESOLVER_SWITCH_TO_WORK"; + + /** + * Title for a dialog shown when the user has no apps capable of handling an intent + * in the personal profile, and must choose whether to open the intent in a + * cross-profile app in the work profile, or open in the same profile browser. Accepts + * the app name as a param. + */ public static final String MINIRESOLVER_OPEN_IN_WORK = PREFIX + "MINIRESOLVER_OPEN_IN_WORK"; + /** + * Title for a dialog shown when the user has no apps capable of handling an intent + * in the personal profile, and must choose whether to open the intent in a + * cross-profile app in the personal profile, or open in the same profile browser. + * Accepts the app name as a param. + */ public static final String MINIRESOLVER_OPEN_IN_PERSONAL = PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL"; diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 904fb665335b9..db65cb37234b6 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -19,7 +19,11 @@ package com.android.internal.app; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL; import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK; +import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_CALL_FROM_WORK; import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_WORK; +import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_SWITCH_TO_WORK; +import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_WORK_TELEPHONY_CALL_BLOCKED_INFORMATION; +import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_WORK_TELEPHONY_TEXT_BLOCKED_INFORMATION; import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -32,6 +36,7 @@ import android.app.Activity; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; +import android.app.admin.ManagedSubscriptionsPolicy; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; @@ -41,6 +46,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; +import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.Build; import android.os.Bundle; @@ -48,6 +54,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telecom.TelecomManager; import android.util.Slog; import android.view.View; import android.widget.Button; @@ -203,35 +210,116 @@ public class IntentForwarderActivity extends Activity { findViewById(R.id.title_container).setElevation(0); - ImageView icon = findViewById(R.id.icon); PackageManager packageManagerForTargetUser = createContextAsUser(UserHandle.of(targetUserId), /* flags= */ 0) .getPackageManager(); - icon.setImageDrawable(target.loadIcon(packageManagerForTargetUser)); + + ImageView icon = findViewById(R.id.icon); + icon.setImageDrawable( + getAppIcon(target, launchIntent, targetUserId, packageManagerForTargetUser)); View buttonContainer = findViewById(R.id.button_bar_container); buttonContainer.setPadding(0, 0, 0, buttonContainer.getPaddingBottom()); ((TextView) findViewById(R.id.open_cross_profile)).setText( - getOpenInWorkMessage(target.loadLabel(packageManagerForTargetUser))); + getOpenInWorkMessage(launchIntent, target.loadLabel(packageManagerForTargetUser))); // The mini-resolver's negative button is reused in this flow to cancel the intent ((Button) findViewById(R.id.use_same_profile_browser)).setText(R.string.cancel); findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish()); + ((Button) findViewById(R.id.button_open)).setText(getOpenInWorkButtonString(launchIntent)); findViewById(R.id.button_open).setOnClickListener(v -> { startActivityAsCaller(launchIntent, targetUserId); finish(); }); + + + View telephonyInfo = findViewById(R.id.miniresolver_info_section); + DevicePolicyManager devicePolicyManager = + getSystemService(DevicePolicyManager.class); + // Additional information section is work telephony specific. Therefore, it is only shown + // for telephony related intents, when all sim subscriptions are in the work profile. + if ((isDialerIntent(launchIntent) || isTextMessageIntent(launchIntent)) + && devicePolicyManager.getManagedSubscriptionsPolicy().getPolicyType() + == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) { + telephonyInfo.setVisibility(View.VISIBLE); + ((TextView) findViewById(R.id.miniresolver_info_section_text)) + .setText(getWorkTelephonyInfoSectionMessage(launchIntent)); + } else { + telephonyInfo.setVisibility(View.GONE); + } } - private String getOpenInWorkMessage(CharSequence targetLabel) { + private Drawable getAppIcon( + ResolveInfo target, + Intent launchIntent, + int targetUserId, + PackageManager packageManagerForTargetUser) { + if (isDialerIntent(launchIntent)) { + // The icon for the call intent will be a generic phone icon as the target will be + // the telecom call handler. From the user's perspective, they are being directed + // to the dialer app, so use the icon from that app instead. + TelecomManager telecomManager = + getApplicationContext().getSystemService(TelecomManager.class); + String defaultDialerPackageName = + telecomManager.getDefaultDialerPackage(UserHandle.of(targetUserId)); + try { + return packageManagerForTargetUser + .getApplicationInfo(defaultDialerPackageName, /* flags= */ 0) + .loadIcon(packageManagerForTargetUser); + } catch (PackageManager.NameNotFoundException e) { + // Allow to fall-through to the icon from the target if we can't find the default + // dialer icon. + Slog.w(TAG, "Cannot load icon for default dialer package"); + } + } + return target.loadIcon(packageManagerForTargetUser); + } + + private int getOpenInWorkButtonString(Intent launchIntent) { + if (isDialerIntent(launchIntent)) { + return R.string.miniresolver_call; + } + if (isTextMessageIntent(launchIntent)) { + return R.string.miniresolver_switch; + } + return R.string.whichViewApplicationLabel; + } + + private String getOpenInWorkMessage(Intent launchIntent, CharSequence targetLabel) { + if (isDialerIntent(launchIntent)) { + return getSystemService(DevicePolicyManager.class).getResources().getString( + MINIRESOLVER_CALL_FROM_WORK, + () -> getString(R.string.miniresolver_call_in_work)); + } + if (isTextMessageIntent(launchIntent)) { + return getSystemService(DevicePolicyManager.class).getResources().getString( + MINIRESOLVER_SWITCH_TO_WORK, + () -> getString(R.string.miniresolver_switch_to_work)); + } return getSystemService(DevicePolicyManager.class).getResources().getString( MINIRESOLVER_OPEN_WORK, () -> getString(R.string.miniresolver_open_work, targetLabel), targetLabel); } + private String getWorkTelephonyInfoSectionMessage(Intent launchIntent) { + if (isDialerIntent(launchIntent)) { + return getSystemService(DevicePolicyManager.class).getResources().getString( + MINIRESOLVER_WORK_TELEPHONY_CALL_BLOCKED_INFORMATION, + () -> getString(R.string.miniresolver_call_information)); + } + if (isTextMessageIntent(launchIntent)) { + return getSystemService(DevicePolicyManager.class).getResources().getString( + MINIRESOLVER_WORK_TELEPHONY_TEXT_BLOCKED_INFORMATION, + () -> getString(R.string.miniresolver_sms_information)); + } + return ""; + } + + + private String getForwardToPersonalMessage() { return getSystemService(DevicePolicyManager.class).getResources().getString( FORWARD_INTENT_TO_PERSONAL, diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml index 1ad3acd7a3eaa..db0ea547fbd50 100644 --- a/core/res/res/layout/miniresolver.xml +++ b/core/res/res/layout/miniresolver.xml @@ -63,6 +63,37 @@ android:textColor="?android:textColorPrimary" /> + + + + + + + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 027d4f8ab2b53..f8a7ece82a521 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -861,10 +861,10 @@ Switch to work profile - + Switch to personal %1$s - + Switch to work %1$s @@ -5918,10 +5918,24 @@ Open in personal %s? Open in work %s? + + Call from work app? + + Switch to work app? + + Your organization only allows you to make calls from work apps + + Your organization only allows you to send messages from work apps Use personal browser Use work browser + + Call + + Switch diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 73e3b417f67ae..cddcff0502ded 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1579,6 +1579,14 @@ + + + + + + + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 70fdc2070b7ab..fef7db436d773 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3093,17 +3093,20 @@ - Can\'t call from this profile + Can\'t call from a personal app - Your work policy allows you to make phone calls only from the work profile + Your organization only allows you to make calls from work apps Switch to work profile + + Install a work phone app - Close + Cancel