diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 54d14f892e258..233f72eaae1f6 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -451,10 +451,14 @@ Your personal apps are blocked until you turn on your work profile - - Your personal apps will be blocked tomorrow + 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] --> + + Personal apps will be blocked on %1$s at + %2$s. Your work profile can\u2019t stay off + for more than %3$d days. + Turn on work profile diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4bc18302f125f..6e830a1488fb0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1200,7 +1200,7 @@ - + diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 0815ee5235554..18c25c1421135 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -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; @@ -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); @@ -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; @@ -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. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 17dd2868f4bc1..724048b1b8ee0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -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 { @@ -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); @@ -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); @@ -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 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() { @Override public boolean matches(Object item) {