diff options
| author | 2015-12-04 15:36:26 +0000 | |
|---|---|---|
| committer | 2016-01-06 16:17:08 +0000 | |
| commit | ea9b10e64419edbd5d3ed13f82007ffed97af418 (patch) | |
| tree | a780c2bf49cdcc32f895391d710457dab2ce93a0 | |
| parent | 514b2cf0f8ddd11a4176412cb3584ab96fbb763a (diff) | |
Work Challenge: Handle Recents launches
Intercept calls to start activities from the recents
stack and show the Work Challenge if needed. This requires
passing the taskId to ConfirmDeviceCredential so it can
launch the recents task itself when the credentials are
confirmed.
Change-Id: I013b134f3f31a35b551ad683c68cc89b8af44499
4 files changed, 85 insertions, 34 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c3dfab48acf5..35cd2bef6093 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3604,6 +3604,15 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID"; /** + * An int representing the task id to be retrieved. This is used when a launch from recents is + * intercepted by another action such as credentials confirmation to remember which task should + * be resumed when complete. + * + * @hide + */ + public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID"; + + /** * An Intent[] describing additional, alternate choices you would like shown with * {@link #ACTION_CHOOSER}. * diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 998f9806095c..e1adc87dd981 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4407,7 +4407,6 @@ public final class ActivityManagerService extends ActivityManagerNative throw new IllegalArgumentException("startActivityFromRecentsInner: Task " + taskId + " can't be launch in the home stack."); } - task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId); if (task == null) { throw new IllegalArgumentException( @@ -4426,7 +4425,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (task.getRootActivity() != null) { + // If the user must confirm credentials (e.g. when first launching a work app and the + // Work Challenge is present) let startActivityInPackage handle the intercepting. + if (!mUserController.shouldConfirmCredentials(task.userId) + && task.getRootActivity() != null) { moveTaskToFrontLocked(task.taskId, 0, bOptions); return ActivityManager.START_TASK_TO_FRONT; } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index f2864d4dd470..f712613a2037 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1,6 +1,7 @@ package com.android.server.am; import static android.app.Activity.RESULT_CANCELED; +import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED; @@ -15,8 +16,16 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.app.PendingIntent.FLAG_ONE_SHOT; +import static android.content.Context.KEYGUARD_SERVICE; +import static android.content.Intent.EXTRA_INTENT; +import static android.content.Intent.EXTRA_PACKAGE_NAME; +import static android.content.Intent.EXTRA_TASK_ID; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; @@ -66,7 +75,6 @@ import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.content.ComponentName; -import android.content.Context; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; @@ -91,7 +99,6 @@ import android.view.Display; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; -import com.android.internal.widget.LockPatternUtils; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.wm.WindowManagerService; @@ -358,37 +365,25 @@ class ActivityStarter { } } - UserInfo user = mSupervisor.getUserInfo(userId); - KeyguardManager km = (KeyguardManager) mService.mContext - .getSystemService(Context.KEYGUARD_SERVICE); - if (user.isManagedProfile() - && LockPatternUtils.isSeparateWorkChallengeEnabled() - && km.isDeviceLocked(userId)) { - IIntentSender target = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, - new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null); - final int flags = intent.getFlags(); - final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id); - if (newIntent != null) { - intent = newIntent; - intent.setFlags(flags - | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName); - intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target)); - - resolvedType = null; - callingUid = realCallingUid; - callingPid = realCallingPid; - - UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId); - rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id); - aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, - null /*profilerInfo*/); + final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(intent, + resolvedType, aInfo, callingPackage, userId); + if (interceptingIntent != null) { + intent = interceptingIntent; + callingPid = realCallingPid; + callingUid = realCallingUid; + resolvedType = null; + // If we are intercepting and there was a task, convert it into an extra for the + // ConfirmCredentials intent and unassign it, as otherwise the task will move to + // front even if ConfirmCredentials is cancelled. + if (inTask != null) { + intent.putExtra(EXTRA_TASK_ID, inTask.taskId); + inTask = null; } + + final UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId); + rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id); + aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, + null /*profilerInfo*/); } if (abort) { @@ -538,6 +533,34 @@ class ActivityStarter { return err; } + /** + * Creates an intent to intercept the current activity start with Confirm Credentials if needed. + * + * @return The intercepting intent if needed. + */ + private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType, + ActivityInfo aInfo, String callingPackage, int userId) { + if (!mService.mUserController.shouldConfirmCredentials(userId)) { + return null; + } + final IIntentSender target = mService.getIntentSenderLocked( + INTENT_SENDER_ACTIVITY, callingPackage, + Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, + new String[]{ resolvedType }, + FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null); + final int flags = intent.getFlags(); + final KeyguardManager km = (KeyguardManager) mService.mContext + .getSystemService(KEYGUARD_SERVICE); + final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); + if (newIntent == null) { + return null; + } + newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName); + newIntent.putExtra(EXTRA_INTENT, new IntentSender(target)); + return newIntent; + } + void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason); startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/, diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index f2c5206f2e1b..717285930f5b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -22,6 +22,7 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM; import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP; import static android.app.ActivityManager.USER_OP_IS_CURRENT; import static android.app.ActivityManager.USER_OP_SUCCESS; +import static android.content.Context.KEYGUARD_SERVICE; import static android.os.Process.SYSTEM_UID; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; @@ -43,6 +44,7 @@ import android.app.AppOpsManager; import android.app.Dialog; import android.app.IStopUserCallback; import android.app.IUserSwitchObserver; +import android.app.KeyguardManager; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; @@ -73,6 +75,7 @@ import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; +import com.android.internal.widget.LockPatternUtils; import com.android.server.pm.UserManagerService; import java.io.PrintWriter; @@ -1286,6 +1289,20 @@ final class UserController { return mCurrentProfileIds; } + /** + * Returns whether the given user requires credential entry at this time. This is used to + * intercept activity launches for work apps when the Work Challenge is present. + */ + boolean shouldConfirmCredentials(int userId) { + final UserInfo user = getUserInfo(userId); + if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) { + return false; + } + final KeyguardManager km = (KeyguardManager) mService.mContext + .getSystemService(KEYGUARD_SERVICE); + return km.isDeviceLocked(user.id); + } + void dump(PrintWriter pw, boolean dumpAll) { pw.println(" mStartedUsers:"); for (int i = 0; i < mStartedUsers.size(); i++) { |