Show notification when work profile switched off
This will notify the user if phone calls and messages
are unavailable.
Screenshots in bug
Bug: 262720433
Test: Manually tested on Pixel 6a
Change-Id: I060c3fa225fe1cf53344d9f8b634e8afbbab468d
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 11b840f..a498913 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1836,6 +1836,27 @@
*/
public static final String WORK_PROFILE_BADGED_LABEL =
PREFIX + "WORK_PROFILE_BADGED_LABEL";
+
+ /**
+ * Notification title. This notification lets the user know that they will be unable to
+ * receive phone calls or texts until the work profile is turned on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_TITLE =
+ PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_TITLE";
+
+ /**
+ * Notification text. This notification lets the user know that they will be unable to
+ * receive phone calls or texts until the work profile is turned on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_BODY =
+ PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_BODY";
+
+ /**
+ * Label for notification button. This button lets the user turn the work profile on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON =
+ PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT";
+
}
/**
diff --git a/core/res/res/drawable/ic_phone_disabled.xml b/core/res/res/drawable/ic_phone_disabled.xml
new file mode 100644
index 0000000..6e60912
--- /dev/null
+++ b/core/res/res/drawable/ic_phone_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M40.65,45.15 L28.9,33.45Q23.55,37.8 18.5,39.925Q13.45,42.05 8.6,42.05Q7.45,42.05 6.7,41.4Q5.95,40.75 5.95,39.75V33Q5.95,32.2 6.45,31.6Q6.95,31 7.7,30.85L13.65,29.55Q14.3,29.4 14.95,29.625Q15.6,29.85 16.1,30.4L20.85,35.3Q22.3,34.6 23.9,33.45Q25.5,32.3 26.75,31.3L3.2,7.7L5.35,5.55L42.8,43.05ZM18.1,36.75 L14.15,32.6Q14.15,32.6 14.15,32.6Q14.15,32.6 14.15,32.6L9,33.65Q9,33.65 9,33.65Q9,33.65 9,33.65V39Q9,39 9,39Q9,39 9,39Q11.25,38.9 13.65,38.3Q16.05,37.7 18.1,36.75ZM33.15,29.15 L31,27Q32.05,25.75 33.125,24.175Q34.2,22.6 35.05,21.3L30.05,16.25Q29.65,15.85 29.5,15.275Q29.35,14.7 29.5,14L30.8,7.75Q30.95,6.95 31.475,6.475Q32,6 32.7,6H39.7Q40.65,6 41.325,6.65Q42,7.3 42,8.25Q42,13.35 39.6,18.975Q37.2,24.6 33.15,29.15ZM36.45,18.45Q37.75,15.45 38.35,13.2Q38.95,10.95 38.9,9Q38.9,9 38.9,9Q38.9,9 38.9,9H33.6Q33.6,9 33.6,9Q33.6,9 33.6,9L32.45,14.45Q32.45,14.45 32.45,14.45Q32.45,14.45 32.45,14.45ZM36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45ZM18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Z"/>
+</vector>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index da44c2e..519869c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -556,6 +556,16 @@
<!-- Title for the button that turns work profile on. To be used in a notification
[CHAR LIMIT=NONE] -->
<string name="personal_apps_suspended_turn_profile_on">Turn on</string>
+ <!-- Notification title. This notification lets the user know that they will be unable to
+ receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=40] -->
+ <string name="work_profile_telephony_paused_title">Calls and messages are off</string>
+ <!-- Notification text. This notification lets the user know that they will be unable to
+ receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=NONE] -->
+ <string name="work_profile_telephony_paused_text">You have paused work apps.
+ You won\'t receive phone calls or text messages.</string>
+ <!-- Label for notification button. This button lets the user turn the work profile on.
+ [CHAR LIMIT=15] -->
+ <string name="work_profile_telephony_paused_turn_on_button">Unpause work apps</string>
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 18084d8..8818e73 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1189,6 +1189,9 @@
<java-symbol type="string" name="personal_apps_suspension_soon_text" />
<java-symbol type="string" name="personal_apps_suspension_text" />
<java-symbol type="string" name="personal_apps_suspended_turn_profile_on" />
+ <java-symbol type="string" name="work_profile_telephony_paused_title" />
+ <java-symbol type="string" name="work_profile_telephony_paused_text" />
+ <java-symbol type="string" name="work_profile_telephony_paused_turn_on_button" />
<java-symbol type="string" name="notification_work_profile_content_description" />
<java-symbol type="string" name="factory_reset_warning" />
<java-symbol type="string" name="factory_reset_message" />
@@ -1409,6 +1412,7 @@
<java-symbol type="drawable" name="btn_borderless_rect" />
<java-symbol type="drawable" name="ic_phone" />
+ <java-symbol type="drawable" name="ic_phone_disabled" />
<java-symbol type="drawable" name="ic_bt_headphones_a2dp" />
<java-symbol type="drawable" name="ic_bt_headset_hfp" />
<java-symbol type="drawable" name="ic_bt_hearing_aid" />
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 12e7226..c9e41c4 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -392,5 +392,11 @@
// Note: this is a base ID, multiple notifications will be posted for each
// abusive apps, with notification ID based off this ID.
NOTE_ABUSIVE_BG_APPS_BASE = 0xc1b2508; // 203105544
+
+ // Notify the user that dialer and sms functionality are unavailable whilst the apps are
+ // paused in the work profile.
+ // Package: android
+ NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF = 1006;
+
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c67ffd5..66adc2c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -134,6 +134,9 @@
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_BODY;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON;
import static android.app.admin.ProvisioningException.ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED;
import static android.app.admin.ProvisioningException.ERROR_PRE_CONDITION_FAILED;
import static android.app.admin.ProvisioningException.ERROR_PROFILE_CREATION_FAILED;
@@ -141,6 +144,8 @@
import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -1118,6 +1123,12 @@
} else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) {
Slogf.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle));
+ } else if (ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+ notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle.of(userHandle), /* managedProfileAvailable= */ false);
+ } else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) {
+ notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle.of(userHandle), /* managedProfileAvailable= */ true);
}
}
@@ -1960,7 +1971,8 @@
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
@@ -18380,6 +18392,83 @@
});
}
+ private void notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle managedProfile, boolean managedProfileAvailable) {
+ if (!isManagedProfile(managedProfile.getIdentifier())) {
+ Slog.wtf(
+ LOG_TAG,
+ "Expected managed profile when notified of profile availability change.");
+ }
+ if (getManagedSubscriptionsPolicy().getPolicyType()
+ != ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ // There may be a subscription in the personal profile, in which case calls and
+ // texts may still be available. No need to notify the user.
+ return;
+ }
+ if (managedProfileAvailable) {
+ // When quiet mode is switched off calls and texts then become available to the user,
+ // so no need to keep showing the notification.
+ mInjector
+ .getNotificationManager()
+ .cancel(SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF);
+ return;
+ }
+ final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, managedProfile.getIdentifier());
+ final PendingIntent pendingIntent =
+ mInjector.pendingIntentGetBroadcast(
+ mContext,
+ /* requestCode= */ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ final Notification.Action turnProfileOnButton =
+ new Notification.Action.Builder(
+ /* icon= */ null, getUnpauseWorkAppsButtonText(), pendingIntent)
+ .build();
+
+ final Bundle extras = new Bundle();
+ extras.putString(
+ Notification.EXTRA_SUBSTITUTE_APP_NAME, getWorkProfileContentDescription());
+ final Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(R.drawable.ic_phone_disabled)
+ .setContentTitle(getUnpauseWorkAppsForTelephonyTitle())
+ .setContentText(getUnpauseWorkAppsForTelephonyText())
+ .setStyle(new Notification.BigTextStyle().bigText(
+ getUnpauseWorkAppsForTelephonyText()))
+ .addAction(turnProfileOnButton)
+ .addExtras(extras)
+ .setOngoing(false)
+ .setShowWhen(true)
+ .setAutoCancel(true)
+ .build();
+
+ mInjector
+ .getNotificationManager()
+ .notifyAsUser(
+ /* tag= */ null,
+ SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF,
+ notification,
+ UserHandle.of(getProfileParentId(managedProfile.getIdentifier())));
+ }
+
+ private String getUnpauseWorkAppsButtonText() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON,
+ R.string.work_profile_telephony_paused_turn_on_button);
+ }
+
+ private String getUnpauseWorkAppsForTelephonyTitle() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_TITLE, R.string.work_profile_telephony_paused_title);
+ }
+
+ private String getUnpauseWorkAppsForTelephonyText() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_BODY,
+ R.string.work_profile_telephony_paused_text);
+ }
+
@GuardedBy("getLockObject()")
private void updateProfileOffDeadlineNotificationLocked(
int profileUserId, ActiveAdmin profileOwner, int notificationState) {