Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.server.am;
     18 
     19 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
     20 import static android.view.Display.DEFAULT_DISPLAY;
     21 import static android.view.Display.INVALID_DISPLAY;
     22 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
     23 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
     24 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
     25 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
     26 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
     27 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
     28 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
     29 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
     30 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
     31 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
     32 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
     33 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
     34 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
     35 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
     36 import static android.view.WindowManager.TRANSIT_UNSET;
     37 
     38 import android.app.ActivityManagerInternal.SleepToken;
     39 import android.os.IBinder;
     40 import android.os.RemoteException;
     41 import android.os.Trace;
     42 import android.util.Slog;
     43 import android.util.proto.ProtoOutputStream;
     44 
     45 import com.android.internal.policy.IKeyguardDismissCallback;
     46 import com.android.server.policy.WindowManagerPolicy;
     47 import com.android.server.wm.WindowManagerService;
     48 
     49 import java.io.PrintWriter;
     50 
     51 /**
     52  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
     53  * currently visible.
     54  * <p>
     55  * Note that everything in this class should only be accessed with the AM lock being held.
     56  */
     57 class KeyguardController {
     58 
     59     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
     60 
     61     private final ActivityManagerService mService;
     62     private final ActivityStackSupervisor mStackSupervisor;
     63     private WindowManagerService mWindowManager;
     64     private boolean mKeyguardShowing;
     65     private boolean mAodShowing;
     66     private boolean mKeyguardGoingAway;
     67     private boolean mOccluded;
     68     private boolean mDismissalRequested;
     69     private ActivityRecord mDismissingKeyguardActivity;
     70     private int mBeforeUnoccludeTransit;
     71     private int mVisibilityTransactionDepth;
     72     private SleepToken mSleepToken;
     73     private int mSecondaryDisplayShowing = INVALID_DISPLAY;
     74 
     75     KeyguardController(ActivityManagerService service,
     76             ActivityStackSupervisor stackSupervisor) {
     77         mService = service;
     78         mStackSupervisor = stackSupervisor;
     79     }
     80 
     81     void setWindowManager(WindowManagerService windowManager) {
     82         mWindowManager = windowManager;
     83     }
     84 
     85     /**
     86      * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
     87      *         on the given display, false otherwise
     88      */
     89     boolean isKeyguardOrAodShowing(int displayId) {
     90         return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
     91                 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
     92     }
     93 
     94     /**
     95      * @return true if Keyguard is showing, not going away, and not being occluded on the given
     96      *         display, false otherwise
     97      */
     98     boolean isKeyguardShowing(int displayId) {
     99         return mKeyguardShowing && !mKeyguardGoingAway &&
    100                 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
    101     }
    102 
    103     /**
    104      * @return true if Keyguard is either showing or occluded, but not going away
    105      */
    106     boolean isKeyguardLocked() {
    107         return mKeyguardShowing && !mKeyguardGoingAway;
    108     }
    109 
    110     /**
    111      * @return {@code true} if the keyguard is going away, {@code false} otherwise.
    112      */
    113     boolean isKeyguardGoingAway() {
    114         // Also check keyguard showing in case value is stale.
    115         return mKeyguardGoingAway && mKeyguardShowing;
    116     }
    117 
    118     /**
    119      * Update the Keyguard showing state.
    120      */
    121     void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
    122             int secondaryDisplayShowing) {
    123         boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
    124         // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
    125         showingChanged |= mKeyguardGoingAway && keyguardShowing;
    126         if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
    127             return;
    128         }
    129         mKeyguardShowing = keyguardShowing;
    130         mAodShowing = aodShowing;
    131         mSecondaryDisplayShowing = secondaryDisplayShowing;
    132         mWindowManager.setAodShowing(aodShowing);
    133         if (showingChanged) {
    134             dismissDockedStackIfNeeded();
    135             setKeyguardGoingAway(false);
    136             mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
    137                     isKeyguardOrAodShowing(DEFAULT_DISPLAY));
    138             if (keyguardShowing) {
    139                 mDismissalRequested = false;
    140             }
    141         }
    142         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    143         updateKeyguardSleepToken();
    144     }
    145 
    146     /**
    147      * Called when Keyguard is going away.
    148      *
    149      * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
    150      *              etc.
    151      */
    152     void keyguardGoingAway(int flags) {
    153         if (!mKeyguardShowing) {
    154             return;
    155         }
    156         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
    157         mWindowManager.deferSurfaceLayout();
    158         try {
    159             setKeyguardGoingAway(true);
    160             mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
    161                     false /* alwaysKeepCurrent */, convertTransitFlags(flags),
    162                     false /* forceOverride */);
    163             updateKeyguardSleepToken();
    164 
    165             // Some stack visibility might change (e.g. docked stack)
    166             mStackSupervisor.resumeFocusedStackTopActivityLocked();
    167             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    168             mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
    169             mWindowManager.executeAppTransition();
    170         } finally {
    171             Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
    172             mWindowManager.continueSurfaceLayout();
    173             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    174 
    175             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    176         }
    177     }
    178 
    179     void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) {
    180         final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
    181         if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
    182             failCallback(callback);
    183             return;
    184         }
    185         Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
    186 
    187         // If the client has requested to dismiss the keyguard and the Activity has the flag to
    188         // turn the screen on, wakeup the screen if it's the top Activity.
    189         if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
    190             mStackSupervisor.wakeUp("dismissKeyguard");
    191         }
    192 
    193         mWindowManager.dismissKeyguard(callback, message);
    194     }
    195 
    196     private void setKeyguardGoingAway(boolean keyguardGoingAway) {
    197         mKeyguardGoingAway = keyguardGoingAway;
    198         mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
    199     }
    200 
    201     private void failCallback(IKeyguardDismissCallback callback) {
    202         try {
    203             callback.onDismissError();
    204         } catch (RemoteException e) {
    205             Slog.w(TAG, "Failed to call callback", e);
    206         }
    207     }
    208 
    209     private int convertTransitFlags(int keyguardGoingAwayFlags) {
    210         int result = 0;
    211         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
    212             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
    213         }
    214         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
    215             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
    216         }
    217         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
    218             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
    219         }
    220         return result;
    221     }
    222 
    223     /**
    224      * Starts a batch of visibility updates.
    225      */
    226     void beginActivityVisibilityUpdate() {
    227         mVisibilityTransactionDepth++;
    228     }
    229 
    230     /**
    231      * Ends a batch of visibility updates. After all batches are done, this method makes sure to
    232      * update lockscreen occluded/dismiss state if needed.
    233      */
    234     void endActivityVisibilityUpdate() {
    235         mVisibilityTransactionDepth--;
    236         if (mVisibilityTransactionDepth == 0) {
    237             visibilitiesUpdated();
    238         }
    239     }
    240 
    241     /**
    242      * @return True if we may show an activity while Keyguard is showing because we are in the
    243      *         process of dismissing it anyways, false otherwise.
    244      */
    245     boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
    246 
    247         // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
    248         // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
    249         // Keyguard.
    250         return dismissKeyguard && canDismissKeyguard() && !mAodShowing
    251                 && (mDismissalRequested || r != mDismissingKeyguardActivity);
    252     }
    253 
    254     /**
    255      * @return True if we may show an activity while Keyguard is occluded, false otherwise.
    256      */
    257     boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
    258         return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
    259     }
    260 
    261     private void visibilitiesUpdated() {
    262         final boolean lastOccluded = mOccluded;
    263         final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
    264         mOccluded = false;
    265         mDismissingKeyguardActivity = null;
    266 
    267         for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
    268             final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
    269             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
    270                 final ActivityStack stack = display.getChildAt(stackNdx);
    271 
    272                 // Only the top activity of the focused stack on the default display may control
    273                 // occluded state.
    274                 if (display.mDisplayId == DEFAULT_DISPLAY
    275                         && mStackSupervisor.isFocusedStack(stack)) {
    276 
    277                     // A dismissing activity occludes Keyguard in the insecure case for legacy
    278                     // reasons.
    279                     final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
    280                     mOccluded =
    281                             stack.topActivityOccludesKeyguard()
    282                                     || (topDismissing != null
    283                                             && stack.topRunningActivityLocked() == topDismissing
    284                                             && canShowWhileOccluded(
    285                                                     true /* dismissKeyguard */,
    286                                                     false /* showWhenLocked */));
    287                 }
    288 
    289                 if (mDismissingKeyguardActivity == null
    290                         && stack.getTopDismissingKeyguardActivity() != null) {
    291                     mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
    292                 }
    293             }
    294         }
    295         mOccluded |= mWindowManager.isShowingDream();
    296         if (mOccluded != lastOccluded) {
    297             handleOccludedChanged();
    298         }
    299         if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
    300             handleDismissKeyguard();
    301         }
    302     }
    303 
    304     /**
    305      * Called when occluded state changed.
    306      */
    307     private void handleOccludedChanged() {
    308         mWindowManager.onKeyguardOccludedChanged(mOccluded);
    309         if (isKeyguardLocked()) {
    310             mWindowManager.deferSurfaceLayout();
    311             try {
    312                 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
    313                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
    314                 updateKeyguardSleepToken();
    315                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    316                 mWindowManager.executeAppTransition();
    317             } finally {
    318                 mWindowManager.continueSurfaceLayout();
    319             }
    320         }
    321         dismissDockedStackIfNeeded();
    322     }
    323 
    324     /**
    325      * Called when somebody might want to dismiss the Keyguard.
    326      */
    327     private void handleDismissKeyguard() {
    328         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
    329         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
    330         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
    331         if (!mOccluded && mDismissingKeyguardActivity != null
    332                 && mWindowManager.isKeyguardSecure()) {
    333             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
    334             mDismissalRequested = true;
    335 
    336             // If we are about to unocclude the Keyguard, but we can dismiss it without security,
    337             // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
    338             if (mKeyguardShowing && canDismissKeyguard()
    339                     && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
    340                 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
    341                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
    342                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    343                 mWindowManager.executeAppTransition();
    344             }
    345         }
    346     }
    347 
    348     /**
    349      * @return true if Keyguard can be currently dismissed without entering credentials.
    350      */
    351     boolean canDismissKeyguard() {
    352         return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
    353     }
    354 
    355     private int resolveOccludeTransit() {
    356         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
    357                 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
    358                 && mOccluded) {
    359 
    360             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
    361             // actually occclude/unocclude Keyguard, but just run a normal transition.
    362             return mBeforeUnoccludeTransit;
    363         } else if (!mOccluded) {
    364 
    365             // Save transit in case we dismiss/occlude Keyguard shortly after.
    366             mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
    367             return TRANSIT_KEYGUARD_UNOCCLUDE;
    368         } else {
    369             return TRANSIT_KEYGUARD_OCCLUDE;
    370         }
    371     }
    372 
    373     private void dismissDockedStackIfNeeded() {
    374         if (mKeyguardShowing && mOccluded) {
    375             // The lock screen is currently showing, but is occluded by a window that can
    376             // show on top of the lock screen. In this can we want to dismiss the docked
    377             // stack since it will be complicated/risky to try to put the activity on top
    378             // of the lock screen in the right fullscreen configuration.
    379             final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
    380             if (stack == null) {
    381                 return;
    382             }
    383             mStackSupervisor.moveTasksToFullscreenStackLocked(stack,
    384                     mStackSupervisor.mFocusedStack == stack);
    385         }
    386     }
    387 
    388     private void updateKeyguardSleepToken() {
    389         if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
    390             mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
    391         } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
    392             mSleepToken.release();
    393             mSleepToken = null;
    394         }
    395     }
    396 
    397     void dump(PrintWriter pw, String prefix) {
    398         pw.println(prefix + "KeyguardController:");
    399         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
    400         pw.println(prefix + "  mAodShowing=" + mAodShowing);
    401         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
    402         pw.println(prefix + "  mOccluded=" + mOccluded);
    403         pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
    404         pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);
    405         pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
    406     }
    407 
    408     void writeToProto(ProtoOutputStream proto, long fieldId) {
    409         final long token = proto.start(fieldId);
    410         proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
    411         proto.write(KEYGUARD_OCCLUDED, mOccluded);
    412         proto.end(token);
    413     }
    414 }
    415