Android 7.1 SystemUI--任务管理

识字粗堪供赋役,不须辛苦慕公卿。这篇文章主要讲述Android 7.1 SystemUI--任务管理相关的知识,希望能为你提供帮助。
场景一 长按某个缩略图,然后拖动分屏的流程1. RecentsView.java
/**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
  */
public class RecentsView extends FrameLayout {

private RecentsViewTouchHandler mTouchHandler; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mTouchHandler.onInterceptTouchEvent(ev); }@Override public boolean onTouchEvent(MotionEvent ev) { return mTouchHandler.onTouchEvent(ev); }

}
 
2. RecentsViewTouchHandler.java
/**
  * Handles touch events for a RecentsView.
  */
public class RecentsViewTouchHandler {
/** Touch preprocessing for handling below */ public boolean onInterceptTouchEvent(MotionEvent ev) { handleTouchEvent(ev); return mDragRequested; }/** Handles touch events once we have intercepted them */ public boolean onTouchEvent(MotionEvent ev) { handleTouchEvent(ev); return mDragRequested; }....../** * Handles dragging touch events */ private void handleTouchEvent(MotionEvent ev) { int action = ev.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: mDownPos.set((int) ev.getX(), (int) ev.getY()); break; case MotionEvent.ACTION_MOVE: { float evX = ev.getX(); float evY = ev.getY(); float x = evX - mTaskViewOffset.x; float y = evY - mTaskViewOffset.y; if (mDragRequested) { if (!mIsDragging) { mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop; } if (mIsDragging) { int width = mRv.getMeasuredWidth(); int height = mRv.getMeasuredHeight(); DropTarget currentDropTarget = null; // Give priority to the current drop target to retain the touch handling if (mLastDropTarget != null) { if (mLastDropTarget.acceptsDrop((int) evX, (int) evY, width, height, mRv.mSystemInsets, true /* isCurrentTarget */)) { currentDropTarget = mLastDropTarget; } }// Otherwise, find the next target to handle this event if (currentDropTarget == null) { for (DropTarget target : mDropTargets) { if (target.acceptsDrop((int) evX, (int) evY, width, height, mRv.mSystemInsets, false /* isCurrentTarget */)) { currentDropTarget = target; break; } } } if (mLastDropTarget != currentDropTarget) { mLastDropTarget = currentDropTarget; EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, currentDropTarget)); }}mTaskView.setTranslationX(x); mTaskView.setTranslationY(y); } break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { if (mDragRequested) { boolean cancelled = action == MotionEvent.ACTION_CANCEL; if (cancelled) { EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, null)); } EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, !cancelled ? mLastDropTarget : null)); break; } } } }

}
 
3. RecentsView.java
public final void onBusEvent(final DragEndEvent event) { // Handle the case where we drop onto a dock region if (event.dropTarget instanceof TaskStack.DockState) { final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; // Hide the dock region updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1, false /* animateAlpha */, false /* animateBounds */); // We translated the view but we need to animate it back from the current layout-space // rect to its final layout-space rect Utilities.setViewFrameFromTranslation(event.taskView); // Dock the task and launch it SystemServicesProxy ssp = Recents.getSystemServices();
// 触发分屏 if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) { final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() { @Override public void onAnimationStarted() { EventBus.getDefault().send(new DockedFirstAnimationFrameEvent()); // Remove the task and don‘t bother relaying out, as all the tasks will be // relaid out when the stack changes on the multiwindow change event mTaskStackView.getStack().removeTask(event.task, null, true /* fromDockGesture */); } }; final Rect taskRect = getTaskRect(event.taskView); IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture( new AnimationSpecComposer() { @Override public List< AppTransitionAnimationSpec> composeSpecs() { return mTransitionHelper.composeDockAnimationSpec( event.taskView, taskRect); } }); ssp.overridePendingAppTransitionMultiThumbFuture(future, mTransitionHelper.wrapStartedListener(startedListener), true /* scaleUp */); MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, event.task.getTopComponent().flattenToShortString()); } else { EventBus.getDefault().send(new DragEndCancelledEvent(mStack, event.task, event.taskView)); } } else { // Animate the overlay alpha back to 0 updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1, true /* animateAlpha */, false /* animateBounds */); }// Show the stack action button again without changing visibility if (mStackActionButton != null) { mStackActionButton.animate() .alpha(1f) .setDuration(SHOW_STACK_ACTION_BUTTON_DURATION) .setInterpolator(Interpolators.ALPHA_IN) .start(); } }

 
 
4.SystemServicesProxy.java 
触发分屏
/** Docks a task to the side of the screen and starts it. */ public boolean startTaskInDockedMode(int taskId, int createMode) { if (mIam == null) return false; try { final ActivityOptions options = ActivityOptions.makeBasic(); options.setDockCreateMode(createMode); options.setLaunchStackId(DOCKED_STACK_ID); mIam.startActivityFromRecents(taskId, options.toBundle()); return true; } catch (Exception e) { Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e); } return false; }

 
 
5.ActivityManagerService.java
@Override public final int startActivityFromRecents(int taskId, Bundle bOptions) {
// 权限检查 if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: startActivityFromRecents called without " + START_TASKS_FROM_RECENTS; Slog.w(TAG, msg); throw new SecurityException(msg); } final long origId = Binder.clearCallingIdentity(); // 清除id,更换调用身份,升级权限 try { synchronized (this) { return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions); } } finally { Binder.restoreCallingIdentity(origId); } }

 
mStackSupervisor 是 ActivityStackSupervisor对象
 
6.ActivityStackSupervisor.java
final int startActivityFromRecentsInner(int taskId, Bundle bOptions) { final TaskRecord task; final int callingUid; final String callingPackage; final Intent intent; final int userId; final ActivityOptions activityOptions = (bOptions != null) ? new ActivityOptions(bOptions) : null; final int launchStackId = (activityOptions != null) ? activityOptions.getLaunchStackId() : INVALID_STACK_ID; if (launchStackId == HOME_STACK_ID) { throw new IllegalArgumentException("startActivityFromRecentsInner: Task " + taskId + " can‘t be launch in the home stack."); }if (launchStackId == DOCKED_STACK_ID) { mWindowManager.setDockedStackCreateState( activityOptions.getDockCreateMode(), null /* initialBounds */); // Defer updating the stack in which recents is until the app transition is done, to // not run into issues where we still need to draw the task in recents but the // docked stack is already created. deferUpdateBounds(HOME_STACK_ID); mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false); }task = anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId); if (task == null) { continueUpdateBounds(HOME_STACK_ID); mWindowManager.executeAppTransition(); throw new IllegalArgumentException( "startActivityFromRecentsInner: Task " + taskId + " not found."); }// Since we don‘t have an actual source record here, we assume that the currently focused // activity was the source. final ActivityStack focusedStack = getFocusedStack(); final ActivityRecord sourceRecord = focusedStack != null ? focusedStack.topActivity() : null; if (launchStackId != INVALID_STACK_ID) { if (task.stack.mStackId != launchStackId) { moveTaskToStackLocked( taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents", ANIMATE); } }
// 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 (!mService.mUserController.shouldConfirmCredentials(task.userId) & & task.getRootActivity() != null) { mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */); mActivityMetricsLogger.notifyActivityLaunching(); mService.moveTaskToFrontLocked(task.taskId, 0, bOptions); mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT, task.getTopActivity()); // If we are launching the task in the docked stack, put it into resizing mode so // the window renders full-screen with the background filling the void. Also only // call this at the end to make sure that tasks exists on the window manager side. if (launchStackId == DOCKED_STACK_ID) { setResizingDuringAnimation(taskId); }mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT, sourceRecord != null ? sourceRecord.task.stack.mStackId : INVALID_STACK_ID, sourceRecord, task.stack); return ActivityManager.START_TASK_TO_FRONT; } callingUid = task.mCallingUid; callingPackage = task.mCallingPackage; intent = task.intent; intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); userId = task.userId; int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null, null, null, 0, 0, bOptions, userId, null, task); if (launchStackId == DOCKED_STACK_ID) { setResizingDuringAnimation(task.taskId); } return result; }

 
mService.mUserController.shouldConfirmCredentials(task.userId)
 
延伸:
1. UserController.java  // 拦截应用启动?
/** * 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) { synchronized (mService) { if (mStartedUsers.get(userId) == null) { return false; } } if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { return false; } final KeyguardManager km = (KeyguardManager) mService.mContext .getSystemService(KEYGUARD_SERVICE); return km.isDeviceLocked(userId) & & km.isDeviceSecure(userId); }

 
延伸:
2.ActivityStarter.java  //应用锁实现?
      private ActivityStartInterceptor mInterceptor;
final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container, TaskRecord inTask) { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; if (caller != null) { callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { callingPid = callerApp.pid; callingUid = callerApp.info.uid; } else { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); err = ActivityManager.START_PERMISSION_DENIED; } }final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; if (err == ActivityManager.START_SUCCESS) { Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ? Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) : (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : container.mActivityDisplay.mDisplayId))); }ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) { sourceRecord = mSupervisor.isInAnyStackLocked(resultTo); if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord); if (sourceRecord != null) { if (requestCode > = 0 & & !sourceRecord.finishing) { resultRecord = sourceRecord; } } }final int launchFlags = intent.getFlags(); if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 & & sourceRecord != null) { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode > = 0) { ActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; if (resultRecord != null & & !resultRecord.isInStackLocked()) { resultRecord = null; } resultWho = sourceRecord.resultWho; requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode); } if (sourceRecord.launchedFromUid == callingUid) { // The new activity is being launched from the same uid as the previous // activity in the flow, and asking to forward its result back to the // previous.In this case the activity is serving as a trampoline between // the two, so we also want to update its launchedFromPackage to be the // same as the previous activity.Note that this is safe, since we know // these two packages come from the same uid; the caller could just as // well have supplied that same package name itself.This specifially // deals with the case of an intent picker/chooser being launched in the app // flow to redirect to an activity picked by the user, where we want the final // activity to consider it to have been launched by the previous app activity. callingPackage = sourceRecord.launchedFromPackage; } }if (err == ActivityManager.START_SUCCESS & & intent.getComponent() == null) { // We couldn‘t find a class that can handle the given Intent. // That‘s the end of that! err = ActivityManager.START_INTENT_NOT_RESOLVED; }if (err == ActivityManager.START_SUCCESS & & aInfo == null) { // We couldn‘t find the specific class specified in the Intent. // Also the end of the line. err = ActivityManager.START_CLASS_NOT_FOUND; }if (err == ActivityManager.START_SUCCESS & & sourceRecord != null & & sourceRecord.task.voiceSession != null) { // If this activity is being launched as part of a voice session, we need // to ensure that it is safe to do so.If the upcoming activity will also // be part of the voice session, we can only launch it if it has explicitly // said it supports the VOICE category, or it is a part of the calling app. if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 & & sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) { try { intent.addCategory(Intent.CATEGORY_VOICE); if (!AppGlobals.getPackageManager().activitySupportsIntent( intent.getComponent(), intent, resolvedType)) { Slog.w(TAG, "Activity being started in current voice task does not support voice: " + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } }if (err == ActivityManager.START_SUCCESS & & voiceSession != null) { // If the caller is starting a new voice session, just make sure the target // is actually allowing it to run this way. try { if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(), intent, resolvedType)) { Slog.w(TAG, "Activity being started in new voice task does not support: " + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } }final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack; if (err != START_SUCCESS) { if (resultRecord != null) { resultStack.sendActivityResultLocked( -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null); } ActivityOptions.abort(options); return err; }boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp, resultRecord, resultStack, options); abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); if (mService.mController != null) { try { // The Intent we give to the watcher has the extra data // stripped off, since it can contain private information. Intent watchIntent = intent.cloneFilter(); abort |= !mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); } catch (RemoteException e) { mService.mController = null; } }mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage); mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid, options); intent = mInterceptor.mIntent; rInfo = mInterceptor.mRInfo; aInfo = mInterceptor.mAInfo; resolvedType = mInterceptor.mResolvedType; inTask = mInterceptor.mInTask; callingPid = mInterceptor.mCallingPid; callingUid = mInterceptor.mCallingUid; options = mInterceptor.mActivityOptions; if (abort) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null); } // We pretend to the caller that it was really started, but // they will just get a cancel result. ActivityOptions.abort(options); return START_SUCCESS; }// If permissions need a review before any of the app components can run, we // launch the review activity and pass a pending intent to start the activity // we are to launching now after the review is completed. if (Build.PERMISSIONS_REVIEW_REQUIRED & & aInfo != null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, userId)) { IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingUid, userId, null, null, 0, new Intent[]{intent}, new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT, null); final int flags = intent.getFlags(); Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS); newIntent.setFlags(flags | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName); newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target)); if (resultRecord != null) { newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true); } intent = newIntent; resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId); aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); if (DEBUG_PERMISSIONS_REVIEW) { Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ? Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) : (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : container.mActivityDisplay.mDisplayId))); } } }// If we have an ephemeral app, abort the process of launching the resolved intent. // Instead, launch the ephemeral installer. Once the installer is finished, it // starts either the intent we resolved here [on install error] or the ephemeral // app [on install success]. if (rInfo != null & & rInfo.ephemeralResolveInfo != null) { intent = buildEphemeralInstallerIntent(intent, ephemeralIntent, rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType, userId); resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); }ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor, container, options, sourceRecord); if (outActivity != null) { outActivity[0] = r; }if (r.appTimeTracker == null & & sourceRecord != null) { // If the caller didn‘t specify an explicit time tracker, we want to continue // tracking under any it has. r.appTimeTracker = sourceRecord.appTimeTracker; }final ActivityStack stack = mSupervisor.mFocusedStack; if (voiceSession == null & & (stack.mResumedActivity == null || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) { if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid, "Activity start")) { PendingActivityLaunch pal =new PendingActivityLaunch(r, sourceRecord, startFlags, stack, callerApp); mPendingActivityLaunches.add(pal); ActivityOptions.abort(options); return ActivityManager.START_SWITCHES_CANCELED; } }if (mService.mDidAppSwitch) { // This is the second allowed switch since we stopped switches, // so now just generally allow switches.Use case: user presses // home (switches disabled, switch to home, mDidAppSwitch now true); // user taps a home icon (coming from home so allowed, we hit here // and now allow anyone to switch again). mService.mAppSwitchesAllowedTime = 0; } else { mService.mDidAppSwitch = true; }doPendingActivityLaunchesLocked(false); try { mService.mWindowManager.deferSurfaceLayout(); err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask); } finally { mService.mWindowManager.continueSurfaceLayout(); } postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack); return err; }

 
延伸:
3.ActivityStartInterceptor.java
/** * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked} * It‘s initialized */ class ActivityStartInterceptor {private final ActivityManagerService mService; private UserManager mUserManager; private final ActivityStackSupervisor mSupervisor; /* * Per-intent states loaded from ActivityStarter than shouldn‘t be changed by any * interception routines. */ private int mRealCallingPid; private int mRealCallingUid; private int mUserId; private int mStartFlags; private String mCallingPackage; /* * Per-intent states that were load from ActivityStarter and are subject to modifications * by the interception routines. After calling {@link #intercept} the caller should assign * these values back to {@link ActivityStarter#startActivityLocked}‘s local variables. */ Intent mIntent; int mCallingPid; int mCallingUid; ResolveInfo mRInfo; ActivityInfo mAInfo; String mResolvedType; TaskRecord mInTask; ActivityOptions mActivityOptions; ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) { mService = service; mSupervisor = supervisor; }void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, String callingPackage) { mRealCallingPid = realCallingPid; mRealCallingUid = realCallingUid; mUserId = userId; mStartFlags = startFlags; mCallingPackage = callingPackage; }void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) { mUserManager = UserManager.get(mService.mContext); mIntent = intent; mCallingPid = callingPid; mCallingUid = callingUid; mRInfo = rInfo; mAInfo = aInfo; mResolvedType = resolvedType; mInTask = inTask; mActivityOptions = activityOptions; if (interceptSuspendPackageIfNeed()) { // Skip the rest of interceptions as the package is suspended by device admin so // no user action can undo this. return; } if (interceptQuietProfileIfNeeded()) { // If work profile is turned off, skip the work challenge since the profile can only // be unlocked when profile‘s user is running. return; } interceptWorkProfileChallengeIfNeeded(); }private boolean interceptQuietProfileIfNeeded() { // Do not intercept if the user has not turned off the profile if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) { return false; } IIntentSender target = mService.getIntentSenderLocked( INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0, new Intent[] {mIntent}, new String[] {mResolvedType}, FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null); mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, new IntentSender(target)); mCallingPid = mRealCallingPid; mCallingUid = mRealCallingUid; mResolvedType = null; final UserInfo parent = mUserManager.getProfileParent(mUserId); mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); return true; }private boolean interceptSuspendPackageIfNeed() { // Do not intercept if the admin did not suspend the package if (mAInfo == null || mAInfo.applicationInfo == null || (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) { return false; } DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService( DevicePolicyManagerInternal.class); if (devicePolicyManager == null) { return false; } mIntent = devicePolicyManager.createPackageSuspendedDialogIntent( mAInfo.packageName, mUserId); mCallingPid = mRealCallingPid; mCallingUid = mRealCallingUid; mResolvedType = null; final UserInfo parent = mUserManager.getProfileParent(mUserId); if (parent != null) { mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); } else { mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId); } mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); return true; }private boolean interceptWorkProfileChallengeIfNeeded() { final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent, mResolvedType, mAInfo, mCallingPackage, mUserId); if (interceptingIntent == null) { return false; } mIntent = interceptingIntent; mCallingPid = mRealCallingPid; mCallingUid = mRealCallingUid; mResolvedType = 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 (mInTask != null) { mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId); mInTask = null; } if (mActivityOptions == null) { mActivityOptions = ActivityOptions.makeBasic(); }ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity(); if (homeActivityRecord != null & & homeActivityRecord.task != null) { // Showing credential confirmation activity in home task to avoid stopping multi-windowed // mode after showing the full-screen credential confirmation activity. mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId); }final UserInfo parent = mUserManager.getProfileParent(mUserId); mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); return true; }/** * 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; } // Allow direct boot aware activity to be displayed before the user is unlocked. if (aInfo.directBootAware & & mService.mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) { 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 KeyguardManager km = (KeyguardManager) mService.mContext .getSystemService(KEYGUARD_SERVICE); final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); if (newIntent == null) { return null; } newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | FLAG_ACTIVITY_TASK_ON_HOME); newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName); newIntent.putExtra(EXTRA_INTENT, new IntentSender(target)); return newIntent; }}

【Android 7.1 SystemUI--任务管理】 











    推荐阅读