Loading core/res/res/values/strings.xml +8 −4 Original line number Diff line number Diff line Loading @@ -451,10 +451,14 @@ <string name="personal_apps_suspension_text"> Your personal apps are blocked until you turn on your work profile</string> <!-- Notification text. This notification lets a user know that their apps will be blocked tomorrow due to a work policy from their IT admin, and that they need to turn on their work profile to prevent the apps from being blocked. [CHAR LIMIT=NONE] --> <string name="personal_apps_suspension_tomorrow_text"> Your personal apps will be blocked tomorrow</string> at a particular time due to a work policy from their IT admin, and that they need to turn on their work profile to prevent the apps from being blocked. It also explains for how many days the profile is allowed to be off and this number is at least 3. [CHAR LIMIT=NONE] --> <string name="personal_apps_suspension_soon_text"> Personal apps will be blocked on <xliff:g id="date" example="May 29">%1$s</xliff:g> at <xliff:g id="time" example="5:20 PM">%2$s</xliff:g>. Your work profile can\u2019t stay off for more than <xliff:g id="number" example="3">%3$d</xliff:g> days. </string> <!-- 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 work profile</string> Loading core/res/res/values/symbols.xml +1 −1 Original line number Diff line number Diff line Loading @@ -1200,7 +1200,7 @@ <java-symbol type="string" name="location_changed_notification_title" /> <java-symbol type="string" name="location_changed_notification_text" /> <java-symbol type="string" name="personal_apps_suspension_title" /> <java-symbol type="string" name="personal_apps_suspension_tomorrow_text" /> <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="notification_work_profile_content_description" /> Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +32 −23 Original line number Diff line number Diff line Loading @@ -247,6 +247,7 @@ import android.stats.devicepolicy.DevicePolicyEnums; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; Loading Loading @@ -16005,31 +16006,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension( int profileUserId, boolean unlocked) { final boolean suspendedExplicitly; final int deadlineState; final String poPackage; final boolean suspendedByTimeout; synchronized (getLockObject()) { final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId); if (profileOwner != null) { deadlineState = final int deadlineState = updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); suspendedExplicitly = profileOwner.mSuspendPersonalApps; poPackage = profileOwner.info.getPackageName(); suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; Slog.d(LOG_TAG, String.format( "Personal apps suspended explicitly: %b, deadline state: %d", suspendedExplicitly, deadlineState)); final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotificationLocked( profileUserId, profileOwner, notificationState); } else { poPackage = null; suspendedExplicitly = false; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; suspendedByTimeout = false; } } Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d", suspendedExplicitly, deadlineState)); if (poPackage != null) { final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); } final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; final int parentUserId = getProfileParentId(profileUserId); suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout); Loading Loading @@ -16141,9 +16138,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private void updateProfileOffDeadlineNotification( int profileUserId, String profileOwnerPackage, int notificationState) { @GuardedBy("getLockObject()") private void updateProfileOffDeadlineNotificationLocked( int profileUserId, ActiveAdmin profileOwner, int notificationState) { if (notificationState == PROFILE_OFF_DEADLINE_DEFAULT) { mInjector.getNotificationManager().cancel(SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED); return; Loading @@ -16161,11 +16158,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final Notification.Action turnProfileOnButton = new Notification.Action.Builder(null /* icon */, buttonText, pendingIntent).build(); final String text = mContext.getString( notificationState == PROFILE_OFF_DEADLINE_WARNING ? R.string.personal_apps_suspension_tomorrow_text : R.string.personal_apps_suspension_text); final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED; final String text; final boolean ongoing; if (notificationState == PROFILE_OFF_DEADLINE_WARNING) { // Round to the closest integer number of days. final int maxDays = (int) ((profileOwner.mProfileMaximumTimeOffMillis + MS_PER_DAY / 2) / MS_PER_DAY); final String date = DateUtils.formatDateTime( mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_DATE); final String time = DateUtils.formatDateTime( mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_TIME); text = mContext.getString( R.string.personal_apps_suspension_soon_text, date, time, maxDays); ongoing = false; } else { text = mContext.getString(R.string.personal_apps_suspension_text); ongoing = true; } final int color = mContext.getColor(R.color.personal_apps_suspension_notification_color); final Bundle extras = new Bundle(); // TODO: Create a separate string for this. services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +11 −6 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Notification title and text for setManagedProfileMaximumTimeOff tests: private static final String PROFILE_OFF_SUSPENSION_TITLE = "suspension_title"; private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text"; private static final String PROFILE_OFF_SUSPENSION_TOMORROW_TEXT = "suspension_tomorrow_text"; private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text"; @Override protected void setUp() throws Exception { Loading Loading @@ -6331,7 +6331,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Now the user should see a warning notification. verify(getServices().notificationManager, times(1)) .notify(anyInt(), argThat(hasExtra(EXTRA_TITLE, PROFILE_OFF_SUSPENSION_TITLE, EXTRA_TEXT, PROFILE_OFF_SUSPENSION_TOMORROW_TEXT))); EXTRA_TEXT, PROFILE_OFF_SUSPENSION_SOON_TEXT))); // Apps shouldn't be suspended yet. verifyZeroInteractions(getServices().ipackageManager); clearInvocations(getServices().alarmManager); Loading Loading @@ -6482,7 +6482,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // To allow creation of Notification via Notification.Builder mContext.applicationInfo = mRealTestContext.getApplicationInfo(); // Setup notification titles. // Setup resources to render notification titles and texts. when(mServiceContext.resources .getString(R.string.personal_apps_suspension_title)) .thenReturn(PROFILE_OFF_SUSPENSION_TITLE); Loading @@ -6490,14 +6490,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getString(R.string.personal_apps_suspension_text)) .thenReturn(PROFILE_OFF_SUSPENSION_TEXT); when(mServiceContext.resources .getString(R.string.personal_apps_suspension_tomorrow_text)) .thenReturn(PROFILE_OFF_SUSPENSION_TOMORROW_TEXT); .getString(eq(R.string.personal_apps_suspension_soon_text), anyString(), anyString(), anyInt())) .thenReturn(PROFILE_OFF_SUSPENSION_SOON_TEXT); // Make locale available for date formatting: when(mServiceContext.resources.getConfiguration()) .thenReturn(mRealTestContext.getResources().getConfiguration()); clearInvocations(getServices().ipackageManager); } private static Matcher<Notification> hasExtra(String... extras) { assertEquals("Odd numebr of extra key-values", 0, extras.length % 2); assertEquals("Odd number of extra key-values", 0, extras.length % 2); return new BaseMatcher<Notification>() { @Override public boolean matches(Object item) { Loading Loading
core/res/res/values/strings.xml +8 −4 Original line number Diff line number Diff line Loading @@ -451,10 +451,14 @@ <string name="personal_apps_suspension_text"> Your personal apps are blocked until you turn on your work profile</string> <!-- Notification text. This notification lets a user know that their apps will be blocked tomorrow due to a work policy from their IT admin, and that they need to turn on their work profile to prevent the apps from being blocked. [CHAR LIMIT=NONE] --> <string name="personal_apps_suspension_tomorrow_text"> Your personal apps will be blocked tomorrow</string> at a particular time due to a work policy from their IT admin, and that they need to turn on their work profile to prevent the apps from being blocked. It also explains for how many days the profile is allowed to be off and this number is at least 3. [CHAR LIMIT=NONE] --> <string name="personal_apps_suspension_soon_text"> Personal apps will be blocked on <xliff:g id="date" example="May 29">%1$s</xliff:g> at <xliff:g id="time" example="5:20 PM">%2$s</xliff:g>. Your work profile can\u2019t stay off for more than <xliff:g id="number" example="3">%3$d</xliff:g> days. </string> <!-- 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 work profile</string> Loading
core/res/res/values/symbols.xml +1 −1 Original line number Diff line number Diff line Loading @@ -1200,7 +1200,7 @@ <java-symbol type="string" name="location_changed_notification_title" /> <java-symbol type="string" name="location_changed_notification_text" /> <java-symbol type="string" name="personal_apps_suspension_title" /> <java-symbol type="string" name="personal_apps_suspension_tomorrow_text" /> <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="notification_work_profile_content_description" /> Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +32 −23 Original line number Diff line number Diff line Loading @@ -247,6 +247,7 @@ import android.stats.devicepolicy.DevicePolicyEnums; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; Loading Loading @@ -16005,31 +16006,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension( int profileUserId, boolean unlocked) { final boolean suspendedExplicitly; final int deadlineState; final String poPackage; final boolean suspendedByTimeout; synchronized (getLockObject()) { final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId); if (profileOwner != null) { deadlineState = final int deadlineState = updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); suspendedExplicitly = profileOwner.mSuspendPersonalApps; poPackage = profileOwner.info.getPackageName(); suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; Slog.d(LOG_TAG, String.format( "Personal apps suspended explicitly: %b, deadline state: %d", suspendedExplicitly, deadlineState)); final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotificationLocked( profileUserId, profileOwner, notificationState); } else { poPackage = null; suspendedExplicitly = false; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; suspendedByTimeout = false; } } Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d", suspendedExplicitly, deadlineState)); if (poPackage != null) { final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); } final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; final int parentUserId = getProfileParentId(profileUserId); suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout); Loading Loading @@ -16141,9 +16138,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private void updateProfileOffDeadlineNotification( int profileUserId, String profileOwnerPackage, int notificationState) { @GuardedBy("getLockObject()") private void updateProfileOffDeadlineNotificationLocked( int profileUserId, ActiveAdmin profileOwner, int notificationState) { if (notificationState == PROFILE_OFF_DEADLINE_DEFAULT) { mInjector.getNotificationManager().cancel(SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED); return; Loading @@ -16161,11 +16158,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final Notification.Action turnProfileOnButton = new Notification.Action.Builder(null /* icon */, buttonText, pendingIntent).build(); final String text = mContext.getString( notificationState == PROFILE_OFF_DEADLINE_WARNING ? R.string.personal_apps_suspension_tomorrow_text : R.string.personal_apps_suspension_text); final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED; final String text; final boolean ongoing; if (notificationState == PROFILE_OFF_DEADLINE_WARNING) { // Round to the closest integer number of days. final int maxDays = (int) ((profileOwner.mProfileMaximumTimeOffMillis + MS_PER_DAY / 2) / MS_PER_DAY); final String date = DateUtils.formatDateTime( mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_DATE); final String time = DateUtils.formatDateTime( mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_TIME); text = mContext.getString( R.string.personal_apps_suspension_soon_text, date, time, maxDays); ongoing = false; } else { text = mContext.getString(R.string.personal_apps_suspension_text); ongoing = true; } final int color = mContext.getColor(R.color.personal_apps_suspension_notification_color); final Bundle extras = new Bundle(); // TODO: Create a separate string for this.
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +11 −6 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Notification title and text for setManagedProfileMaximumTimeOff tests: private static final String PROFILE_OFF_SUSPENSION_TITLE = "suspension_title"; private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text"; private static final String PROFILE_OFF_SUSPENSION_TOMORROW_TEXT = "suspension_tomorrow_text"; private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text"; @Override protected void setUp() throws Exception { Loading Loading @@ -6331,7 +6331,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Now the user should see a warning notification. verify(getServices().notificationManager, times(1)) .notify(anyInt(), argThat(hasExtra(EXTRA_TITLE, PROFILE_OFF_SUSPENSION_TITLE, EXTRA_TEXT, PROFILE_OFF_SUSPENSION_TOMORROW_TEXT))); EXTRA_TEXT, PROFILE_OFF_SUSPENSION_SOON_TEXT))); // Apps shouldn't be suspended yet. verifyZeroInteractions(getServices().ipackageManager); clearInvocations(getServices().alarmManager); Loading Loading @@ -6482,7 +6482,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // To allow creation of Notification via Notification.Builder mContext.applicationInfo = mRealTestContext.getApplicationInfo(); // Setup notification titles. // Setup resources to render notification titles and texts. when(mServiceContext.resources .getString(R.string.personal_apps_suspension_title)) .thenReturn(PROFILE_OFF_SUSPENSION_TITLE); Loading @@ -6490,14 +6490,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getString(R.string.personal_apps_suspension_text)) .thenReturn(PROFILE_OFF_SUSPENSION_TEXT); when(mServiceContext.resources .getString(R.string.personal_apps_suspension_tomorrow_text)) .thenReturn(PROFILE_OFF_SUSPENSION_TOMORROW_TEXT); .getString(eq(R.string.personal_apps_suspension_soon_text), anyString(), anyString(), anyInt())) .thenReturn(PROFILE_OFF_SUSPENSION_SOON_TEXT); // Make locale available for date formatting: when(mServiceContext.resources.getConfiguration()) .thenReturn(mRealTestContext.getResources().getConfiguration()); clearInvocations(getServices().ipackageManager); } private static Matcher<Notification> hasExtra(String... extras) { assertEquals("Odd numebr of extra key-values", 0, extras.length % 2); assertEquals("Odd number of extra key-values", 0, extras.length % 2); return new BaseMatcher<Notification>() { @Override public boolean matches(Object item) { Loading