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