/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.am; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY; import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE; import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; import java.util.ArrayList; /** * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are * currently visible. *
* Note that everything in this class should only be accessed with the AM lock being held.
*/
class KeyguardController {
private final ActivityManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
private boolean mKeyguardShowing;
private boolean mKeyguardGoingAway;
private boolean mOccluded;
private ActivityRecord mDismissingKeyguardActivity;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
KeyguardController(ActivityManagerService service,
ActivityStackSupervisor stackSupervisor) {
mService = service;
mStackSupervisor = stackSupervisor;
}
void setWindowManager(WindowManagerService windowManager) {
mWindowManager = windowManager;
}
/**
* @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
*/
boolean isKeyguardShowing() {
return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
}
/**
* @return true if Keyguard is either showing or occluded, but not going away
*/
boolean isKeyguardLocked() {
return mKeyguardShowing && !mKeyguardGoingAway;
}
/**
* Update the Keyguard showing state.
*/
void setKeyguardShown(boolean showing) {
if (showing == mKeyguardShowing) {
return;
}
mKeyguardShowing = showing;
if (showing) {
mKeyguardGoingAway = false;
// Allow an activity to redismiss Keyguard.
mDismissingKeyguardActivity = null;
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mService.updateSleepIfNeededLocked();
}
/**
* Called when Keyguard is going away.
*
* @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
* etc.
*/
void keyguardGoingAway(int flags) {
if (mKeyguardShowing) {
mWindowManager.deferSurfaceLayout();
try {
mKeyguardGoingAway = true;
mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
mWindowManager.keyguardGoingAway(flags);
mService.updateSleepIfNeededLocked();
// Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
true /* enable */);
} finally {
mWindowManager.continueSurfaceLayout();
}
}
}
private int convertTransitFlags(int keyguardGoingAwayFlags) {
int result = 0;
if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
}
if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
}
if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
}
return result;
}
/**
* Starts a batch of visibility updates.
*/
void beginActivityVisibilityUpdate() {
mVisibilityTransactionDepth++;
}
/**
* Ends a batch of visibility updates. After all batches are done, this method makes sure to
* update lockscreen occluded/dismiss state if needed.
*/
void endActivityVisibilityUpdate() {
mVisibilityTransactionDepth--;
if (mVisibilityTransactionDepth == 0) {
visibilitiesUpdated();
}
}
/**
* @return True if we may show an activity while Keyguard is showing because we are in the
* process of dismissing it anyways, false otherwise.
*/
boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
return dismissKeyguard && canDismissKeyguard();
}
private void visibilitiesUpdated() {
final boolean lastOccluded = mOccluded;
final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
mOccluded = false;
mDismissingKeyguardActivity = null;
final ArrayList