diff options
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 d77e1a20e0c0..ba3e25aea66c 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<Integer> 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 54df744ad41b..d2ae22b43445 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); @@ -234,6 +238,38 @@ public class LockTaskControllerTest { } @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 TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); @@ -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 92d458f13cd1..6dcc3da15882 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -582,13 +582,21 @@ public class TelecomManager { "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. */ /** * Indicates that the address or number of a call is allowed to be displayed for caller ID. - */ + */ public static final int PRESENTATION_ALLOWED = 1; /** |