Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 853304c0 authored by Tony Mak's avatar Tony Mak
Browse files

Show work challenge in if user in docked stack is locked

Register docked stack listener in ActivityManagerService.
If the docked stack is leaving minimized state, check whether the user
of the docked stack is locked. If yes, show credential confirmation.
Also, we now show work challenge in home task.

And we now scan the entire top task to handle the case the work app is
somewhere in the middle of the task. (eg: open personal camera in work app)

Bug: 27565539
Bug: 28094505

Change-Id: Iaf0738f43ae916a535b17949ec0f322bbfb194dc
parent 739da49d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -133,4 +133,10 @@ public abstract class ActivityManagerInternal {
     * the focused activity.
     */
    public abstract List<IBinder> getTopVisibleActivities();

    /**
     * Callback for window manager to let activity manager know that docked stack changes its
     * minimized state.
     */
    public abstract void notifyDockedStackMinimizedChanged(boolean minimized);
}
+10 −9
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ import android.app.IUiAutomationConnection;
import android.app.IUidObserver;
import android.app.IUserSwitchObserver;
import android.app.Instrumentation;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -11471,20 +11472,13 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        synchronized (this) {
            if (mStackSupervisor.isFocusedUserLockedProfile()) {
            if (mStackSupervisor.isUserLockedProfile(userId)) {
                final long ident = Binder.clearCallingIdentity();
                try {
                    final int currentUserId = mUserController.getCurrentUserIdLocked();
                    // Get the focused task before launching launcher.
                    if (mUserController.isLockScreenDisabled(currentUserId)) {
                        // If there is no device lock, we will show the profile's credential page.
                        // startActivityFromRecentsInner is intercepted and will forward user to it.
                        if (mFocusedActivity != null) {
                            mStackSupervisor.startActivityFromRecentsInner(
                                    mFocusedActivity.task.taskId, null);
                        }
                        mActivityStarter.showConfirmDeviceCredential(userId);
                    } else {
                        // Showing launcher to avoid user entering credential twice.
                        startHomeActivityLocked(currentUserId, "notifyLockedProfile");
@@ -21006,6 +21000,13 @@ public final class ActivityManagerService extends ActivityManagerNative
                return mStackSupervisor.getTopVisibleActivities();
            }
        }
        @Override
        public void notifyDockedStackMinimizedChanged(boolean minimized) {
            synchronized (ActivityManagerService.this) {
                mStackSupervisor.setDockedStackMinimized(minimized);
            }
        }
    }
    private final class SleepTokenImpl extends SleepToken {
+64 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.am;

import android.Manifest;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
@@ -29,6 +30,8 @@ import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.app.IActivityManager;
import android.app.IActivityManager.WaitResult;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.StatusBarManager;
@@ -37,6 +40,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -166,6 +170,7 @@ import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -432,6 +437,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
     */
    private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();

    /**
     * Is dock currently minimized.
     */
    boolean mIsDockMinimized;

    /**
     * Description of a request to start a new activity, which has been held
     * due to app switches being disabled.
@@ -716,10 +726,44 @@ public final class ActivityStackSupervisor implements DisplayListener {
        return null;
    }

    boolean isFocusedUserLockedProfile() {
        final int userId = mFocusedStack.topRunningActivityLocked().userId;
        return userId != UserHandle.myUserId()
                && mService.mUserController.shouldConfirmCredentials(userId);
    /**
     * TODO: Handle freefom mode.
     * @return true when credential confirmation is needed for the user and there is any
     *         activity started by the user in any visible stack.
     */
    boolean isUserLockedProfile(@UserIdInt int userId) {
        if (!mService.mUserController.shouldConfirmCredentials(userId)) {
            return false;
        }
        final ActivityStack fullScreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
        final ActivityStack dockedStack = getStack(DOCKED_STACK_ID);
        final ActivityStack[] activityStacks = new ActivityStack[] {fullScreenStack, dockedStack};
        for (final ActivityStack activityStack : activityStacks) {
            if (activityStack == null) {
                continue;
            }
            if (activityStack.topRunningActivityLocked() == null) {
                continue;
            }
            if (activityStack.getStackVisibilityLocked(null) == STACK_INVISIBLE) {
                continue;
            }
            if (activityStack.isDockedStack() && mIsDockMinimized) {
                continue;
            }
            final TaskRecord topTask = activityStack.topTask();
            if (topTask == null) {
                continue;
            }
            // To handle the case that work app is in the task but just is not the top one.
            for (int i = topTask.mActivities.size() - 1; i >= 0; i--) {
                final ActivityRecord activityRecord = topTask.mActivities.get(i);
                if (activityRecord.userId == userId) {
                    return true;
                }
            }
        }
        return false;
    }

    void setNextTaskIdForUserLocked(int taskId, int userId) {
@@ -3590,6 +3634,22 @@ public final class ActivityStackSupervisor implements DisplayListener {
        }
    }

    void setDockedStackMinimized(boolean minimized) {
        mIsDockMinimized = minimized;
        if (minimized) {
            // Docked stack is not visible, no need to confirm credentials for its top activity.
            return;
        }
        final ActivityStack dockedStack = getStack(StackId.DOCKED_STACK_ID);
        if (dockedStack == null) {
            return;
        }
        final ActivityRecord top = dockedStack.topRunningActivityLocked();
        if (top != null && mService.mUserController.shouldConfirmCredentials(top.userId)) {
            mService.mActivityStarter.showConfirmDeviceCredential(top.userId);
        }
    }

    private final class ActivityStackSupervisorHandler extends Handler {

        public ActivityStackSupervisorHandler(Looper looper) {
+10 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;

import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.IIntentSender;
@@ -76,6 +77,7 @@ class ActivityStartInterceptor {
    ActivityInfo mAInfo;
    String mResolvedType;
    TaskRecord mInTask;
    ActivityOptions mActivityOptions;

    ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
        mService = service;
@@ -92,7 +94,7 @@ class ActivityStartInterceptor {
    }

    void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
            TaskRecord inTask, int callingPid, int callingUid) {
            TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
        mUserManager = UserManager.get(mService.mContext);
        mIntent = intent;
        mCallingPid = callingPid;
@@ -101,6 +103,7 @@ class ActivityStartInterceptor {
        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.
@@ -177,6 +180,12 @@ class ActivityStartInterceptor {
            mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
            mInTask = null;
        }
        if (mActivityOptions == null) {
            mActivityOptions = ActivityOptions.makeBasic();
        }
        // Showing credential confirmation activity in home task to avoid stopping multi-windowed
        // mode after showing the full-screen credential confirmation activity.
        mActivityOptions.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);

        final UserInfo parent = mUserManager.getProfileParent(mUserId);
        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+52 −2
Original line number Diff line number Diff line
@@ -82,9 +82,11 @@ import android.app.AppGlobals;
import android.app.IActivityContainer;
import android.app.IActivityManager;
import android.app.IApplicationThread;
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;
@@ -380,7 +382,8 @@ class ActivityStarter {
        }

        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
        mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid);
        mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
                options);
        intent = mInterceptor.mIntent;
        rInfo = mInterceptor.mRInfo;
        aInfo = mInterceptor.mAInfo;
@@ -388,7 +391,7 @@ class ActivityStarter {
        inTask = mInterceptor.mInTask;
        callingPid = mInterceptor.mCallingPid;
        callingUid = mInterceptor.mCallingUid;

        options = mInterceptor.mActivityOptions;
        if (abort) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
@@ -589,6 +592,53 @@ class ActivityStarter {
        }
    }

    void showConfirmDeviceCredential(int userId) {
        // First, retrieve the stack that we want to resume after credential is confirmed.
        ActivityStack targetStack;
        ActivityStack fullscreenStack =
                mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
        if (fullscreenStack != null &&
                fullscreenStack.getStackVisibilityLocked(null) != ActivityStack.STACK_INVISIBLE) {
            // Single window case and the case that the docked stack is shown with fullscreen stack.
            targetStack = fullscreenStack;
        } else {
            // The case that the docked stack is shown with recent.
            targetStack = mSupervisor.getStack(HOME_STACK_ID);
        }
        if (targetStack == null) {
            return;
        }
        final KeyguardManager km = (KeyguardManager) mService.mContext
                .getSystemService(Context.KEYGUARD_SERVICE);
        final Intent credential =
                km.createConfirmDeviceCredentialIntent(null, null, userId);
        credential.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
        final ActivityRecord activityRecord = targetStack.topRunningActivityLocked();
        if (activityRecord != null) {
            final IIntentSender target = mService.getIntentSenderLocked(
                    ActivityManager.INTENT_SENDER_ACTIVITY,
                    activityRecord.launchedFromPackage,
                    activityRecord.launchedFromUid,
                    activityRecord.userId,
                    null, null, 0,
                    new Intent[] { activityRecord.intent },
                    new String[] { activityRecord.resolvedType },
                    PendingIntent.FLAG_CANCEL_CURRENT |
                            PendingIntent.FLAG_ONE_SHOT |
                            PendingIntent.FLAG_IMMUTABLE,
                    null);
            credential.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
            // Show confirm credentials activity.
            mService.mContext.startActivityAsUser(credential, options.toBundle(),
                    UserHandle.CURRENT);
        }
    }


    final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
Loading