From 858f132e0c988ed38ff17005fd0efaaf5eecb422 Mon Sep 17 00:00:00 2001 From: Charles He Date: Mon, 27 Nov 2017 17:11:04 -0800 Subject: [PATCH] Enable outgoing emergency calls in LockTask mode. As part of the LockTask 2.0 work, we allow DPCs to enable the system lock screen in LockTask mode. When the device is protected by a PIN, pattern, or password, the lock screen will have an entry point to the emergency dialer which allows the user to make emergency calls (e.g., 911). Therefore, we whitelist the activities that are necessary to place this outgoing emergency call when LOCK_TASK_FEATURE_KEYGUARD is enabled. Bug: 68750910 Test: bit FrameworksServicesTests:com.android.server.am.LockTaskControllerTest Test: CTS verifier > CTS verifier > Managed provisioning > Device owner tests > LockTask UI Change-Id: Iaeeec2c462b978d2d201c5660024a3dd7283ae07 --- .../android/server/am/LockTaskController.java | 61 +++++++++++++++++-- .../server/am/LockTaskControllerTest.java | 47 +++++++++++++- .../java/android/telecom/TelecomManager.java | 10 ++- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index d77e1a20e0c00..ba3e25aea66c0 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -22,8 +22,10 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.STATUS_BAR_SERVICE; +import static android.content.Intent.ACTION_CALL_EMERGENCY; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; +import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; @@ -45,6 +47,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.os.Binder; import android.os.Debug; import android.os.Handler; @@ -52,9 +55,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telecom.TelecomManager; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; @@ -133,6 +138,8 @@ public class LockTaskController { WindowManagerService mWindowManager; @VisibleForTesting LockPatternUtils mLockPatternUtils; + @VisibleForTesting + TelecomManager mTelecomManager; /** * Helper that is responsible for showing the right toast when a disallowed activity operation @@ -165,7 +172,7 @@ public class LockTaskController { /** * Features that are allowed by DPC to show during LockTask mode. */ - private final SparseArray mLockTaskFeatures = new SparseArray<>(); + private final SparseIntArray mLockTaskFeatures = new SparseIntArray(); /** * Store the current lock task mode. Possible values: @@ -298,6 +305,11 @@ public class LockTaskController { return false; } + // Allow emergency calling when the device is protected by a locked keyguard + if (isKeyguardAllowed(task.userId) && isEmergencyCallTask(task)) { + return false; + } + return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty()); } @@ -306,6 +318,37 @@ public class LockTaskController { & DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS) != 0; } + private boolean isKeyguardAllowed(int userId) { + return (getLockTaskFeaturesForUser(userId) + & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0; + } + + private boolean isEmergencyCallTask(TaskRecord task) { + final Intent intent = task.intent; + if (intent == null) { + return false; + } + + // 1. The emergency keypad activity launched on top of the keyguard + if (EMERGENCY_DIALER_COMPONENT.equals(intent.getComponent())) { + return true; + } + + // 2. The intent sent by the keypad, which is handled by Telephony + if (ACTION_CALL_EMERGENCY.equals(intent.getAction())) { + return true; + } + + // 3. Telephony then starts the default package for making the call + final TelecomManager tm = getTelecomManager(); + final String dialerPackage = tm != null ? tm.getSystemDialerPackage() : null; + if (dialerPackage != null && dialerPackage.equals(intent.getComponent().getPackageName())) { + return true; + } + + return false; + } + /** * Stop the current lock task mode. * @@ -686,11 +729,10 @@ public class LockTaskController { mWindowManager.reenableKeyguard(mToken); } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) { - int lockTaskFeatures = getLockTaskFeaturesForUser(userId); - if ((DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD & lockTaskFeatures) == 0) { - mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG); - } else { + if (isKeyguardAllowed(userId)) { mWindowManager.reenableKeyguard(mToken); + } else { + mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG); } } else { // lockTaskModeState == LOCK_TASK_MODE_PINNED @@ -784,6 +826,15 @@ public class LockTaskController { return mLockPatternUtils; } + @Nullable + private TelecomManager getTelecomManager() { + if (mTelecomManager == null) { + // We don't preserve the TelecomManager object to save memory + return mContext.getSystemService(TelecomManager.class); + } + return mTelecomManager; + } + // Should only be called on the handler thread @NonNull private LockTaskNotify getLockTaskNotify() { diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java index 54df744ad41b7..d2ae22b43445d 100644 --- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java @@ -30,6 +30,7 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; import static android.os.Process.SYSTEM_UID; +import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_LOCKED; import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_PINNED; @@ -53,6 +54,7 @@ import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; +import android.telecom.TelecomManager; import android.util.Pair; import com.android.internal.statusbar.IStatusBarService; @@ -90,6 +92,7 @@ public class LockTaskControllerTest { @Mock private LockPatternUtils mLockPatternUtils; @Mock private LockTaskNotify mLockTaskNotify; @Mock private StatusBarManagerInternal mStatusBarManagerInternal; + @Mock private TelecomManager mTelecomManager; @Mock private RecentTasks mRecentTasks; private LockTaskController mLockTaskController; @@ -118,6 +121,7 @@ public class LockTaskControllerTest { mLockTaskController.setWindowManager(mWindowManager); mLockTaskController.mStatusBarService = mStatusBarService; mLockTaskController.mDevicePolicyManager = mDevicePolicyManager; + mLockTaskController.mTelecomManager = mTelecomManager; mLockTaskController.mLockPatternUtils = mLockPatternUtils; mLockTaskController.mLockTaskNotify = mLockTaskNotify; @@ -209,7 +213,7 @@ public class LockTaskControllerTest { @Test public void testLockTaskViolation() throws Exception { - // GIVEN one task records with whitelisted auth that is in lock task mode + // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -233,6 +237,38 @@ public class LockTaskControllerTest { TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV))); } + @Test + public void testLockTaskViolation_emergencyCall() throws Exception { + // GIVEN one task record with whitelisted auth that is in lock task mode + TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); + mLockTaskController.startLockTaskMode(tr, false, TEST_UID); + + // GIVEN tasks necessary for emergency calling + TaskRecord keypad = getTaskRecord(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT), + TaskRecord.LOCK_TASK_AUTH_PINNABLE); + TaskRecord callAction = getTaskRecord(new Intent(Intent.ACTION_CALL_EMERGENCY), + TaskRecord.LOCK_TASK_AUTH_PINNABLE); + TaskRecord dialer = getTaskRecord("com.example.dialer", TaskRecord.LOCK_TASK_AUTH_PINNABLE); + when(mTelecomManager.getSystemDialerPackage()) + .thenReturn(dialer.intent.getComponent().getPackageName()); + + // GIVEN keyguard is allowed for lock task mode + mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_KEYGUARD); + + // THEN the above tasks should all be allowed + assertFalse(mLockTaskController.isLockTaskModeViolation(keypad)); + assertFalse(mLockTaskController.isLockTaskModeViolation(callAction)); + assertFalse(mLockTaskController.isLockTaskModeViolation(dialer)); + + // GIVEN keyguard is disallowed for lock task mode (default) + mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NONE); + + // THEN the above tasks should all be blocked + assertTrue(mLockTaskController.isLockTaskModeViolation(keypad)); + assertTrue(mLockTaskController.isLockTaskModeViolation(callAction)); + assertTrue(mLockTaskController.isLockTaskModeViolation(dialer)); + } + @Test public void testStopLockTaskMode() throws Exception { // GIVEN one task record with whitelisted auth that is in lock task mode @@ -568,10 +604,15 @@ public class LockTaskControllerTest { } private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) { + final Intent intent = new Intent() + .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME)); + return getTaskRecord(intent, lockTaskAuth); + } + + private TaskRecord getTaskRecord(Intent intent, int lockTaskAuth) { TaskRecord tr = mock(TaskRecord.class); tr.mLockTaskAuth = lockTaskAuth; - tr.intent = new Intent() - .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME)); + tr.intent = intent; tr.userId = TEST_USER_ID; return tr; } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 92d458f13cd12..6dcc3da158828 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -581,6 +581,14 @@ public class TelecomManager { public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT"; + /** + * The dialer activity responsible for placing emergency calls from, for example, a locked + * keyguard. + * @hide + */ + public static final ComponentName EMERGENCY_DIALER_COMPONENT = + ComponentName.createRelative("com.android.phone", ".EmergencyDialer"); + /** * The following 4 constants define how properties such as phone numbers and names are * displayed to the user. @@ -588,7 +596,7 @@ public class TelecomManager { /** * Indicates that the address or number of a call is allowed to be displayed for caller ID. - */ + */ public static final int PRESENTATION_ALLOWED = 1; /**