blob: 632494b92dc15a83905f64c4ac73c58e5480c3a0 [file] [log] [blame]
/*
* Copyright (C) 2018 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.wm;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
import android.os.Binder;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
import android.view.Display;
import android.view.WindowManager;
import android.view.WindowManager.TransitionType;
import com.android.internal.annotations.VisibleForTesting;
/**
* Controller for the display container. This is created by activity manager to link activity
* displays to the display content they use in window manager.
*/
public class DisplayWindowController
extends WindowContainerController<DisplayContent, WindowContainerListener> {
private final int mDisplayId;
public DisplayWindowController(Display display, WindowContainerListener listener) {
super(listener, WindowManagerService.getInstance());
mDisplayId = display.getDisplayId();
synchronized (mGlobalLock) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
mRoot.createDisplayContent(display, this /* controller */);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
if (mContainer == null) {
throw new IllegalArgumentException("Trying to add display=" + display
+ " dc=" + mRoot.getDisplayContent(mDisplayId));
}
}
}
@VisibleForTesting
public DisplayWindowController(Display display, WindowManagerService service) {
super(null, service);
mDisplayId = display.getDisplayId();
}
@Override
public void removeContainer() {
synchronized (mGlobalLock) {
if(mContainer == null) {
if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
+ mDisplayId);
return;
}
mContainer.removeIfPossible();
super.removeContainer();
}
}
@Override
public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
synchronized (mGlobalLock) {
if (mContainer != null) {
mContainer.mService.setNewDisplayOverrideConfiguration(overrideConfiguration,
mContainer);
}
}
}
/**
* Updates the docked/pinned controller resources to the current system context.
*/
public void preOnConfigurationChanged() {
synchronized (mGlobalLock) {
if (mContainer != null) {
mContainer.preOnConfigurationChanged();
}
}
}
/**
* @see DisplayContent#applyRotationLocked(int, int)
*/
public void applyRotation(int oldRotation, int newRotation) {
synchronized (mGlobalLock) {
if (mContainer != null) {
mContainer.applyRotationLocked(oldRotation, newRotation);
}
}
}
public int getDisplayId() {
return mDisplayId;
}
/**
* Called when the corresponding display receives
* {@link android.hardware.display.DisplayManager.DisplayListener#onDisplayChanged(int)}.
*/
public void onDisplayChanged() {
synchronized (mGlobalLock) {
if (mContainer == null) {
if (DEBUG_DISPLAY) Slog.i(TAG_WM, "onDisplayChanged: could not find display="
+ mDisplayId);
return;
}
mContainer.updateDisplayInfo();
mService.mWindowPlacerLocked.requestTraversal();
}
}
/**
* Positions the task stack at the given position in the task stack container.
*/
public void positionChildAt(StackWindowController child, int position,
boolean includingParents) {
synchronized (mGlobalLock) {
if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskStackAt: positioning stack=" + child
+ " at " + position);
if (mContainer == null) {
if (DEBUG_STACK) Slog.i(TAG_WM,
"positionTaskStackAt: could not find display=" + mContainer);
return;
}
if (child.mContainer == null) {
if (DEBUG_STACK) Slog.i(TAG_WM,
"positionTaskStackAt: could not find stack=" + this);
return;
}
mContainer.positionStackAt(position, child.mContainer, includingParents);
}
}
/**
* Starts deferring the ability to update the IME target. This is needed when a call will
* attempt to update the IME target before all information about the Windows have been updated.
*/
public void deferUpdateImeTarget() {
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
if (dc != null) {
dc.deferUpdateImeTarget();
}
}
}
/**
* Resumes updating the IME target after deferring. See {@link #deferUpdateImeTarget()}
*/
public void continueUpdateImeTarget() {
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
if (dc != null) {
dc.continueUpdateImeTarget();
}
}
}
/**
* Sets a focused app on this display.
*
* @param token Specifies which app should be focused.
* @param moveFocusNow Specifies if we should update the focused window immediately.
*/
public void setFocusedApp(IBinder token, boolean moveFocusNow) {
synchronized (mGlobalLock) {
if (mContainer == null) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "setFocusedApp: could not find displayId="
+ mDisplayId);
return;
}
final AppWindowToken newFocus;
if (token == null) {
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
+ mDisplayId);
newFocus = null;
} else {
newFocus = mRoot.getAppWindowToken(token);
if (newFocus == null) {
Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
+ ", displayId=" + mDisplayId);
}
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
+ " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
}
final boolean changed = mContainer.setFocusedApp(newFocus);
if (moveFocusNow && changed) {
mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
true /*updateInputWindows*/);
}
}
}
public void prepareAppTransition(@WindowManager.TransitionType int transit,
boolean alwaysKeepCurrent) {
prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
}
/**
* @param transit What kind of transition is happening. Use one of the constants
* AppTransition.TRANSIT_*.
* @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
* be set.
* @param flags Additional flags for the app transition, Use a combination of the constants
* AppTransition.TRANSIT_FLAG_*.
* @param forceOverride Always override the transit, not matter what was set previously.
*/
public void prepareAppTransition(@WindowManager.TransitionType int transit,
boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
boolean forceOverride) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId).prepareAppTransition(transit, alwaysKeepCurrent,
flags, forceOverride);
}
}
public void executeAppTransition() {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId).executeAppTransition();
}
}
public void overridePendingAppTransition(String packageName,
int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, startedCallback);
}
}
public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
int startHeight) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransitionScaleUp(
startX, startY, startWidth, startHeight);
}
}
public void overridePendingAppTransitionClipReveal(int startX, int startY,
int startWidth, int startHeight) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overridePendingAppTransitionClipReveal(startX, startY,
startWidth, startHeight);
}
}
public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX,
int startY, IRemoteCallback startedCallback, boolean scaleUp) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
startedCallback, scaleUp);
}
}
public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX,
int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
boolean scaleUp) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX,
startY, targetWidth, targetHeight, startedCallback, scaleUp);
}
}
public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
boolean scaleUp) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overridePendingAppTransitionMultiThumb(specs,
onAnimationStartedCallback, onAnimationFinishedCallback, scaleUp);
}
}
public void overridePendingAppTransitionStartCrossProfileApps() {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overridePendingAppTransitionStartCrossProfileApps();
}
}
public void overridePendingAppTransitionInPlace(String packageName, int anim) {
synchronized (mGlobalLock) {
mRoot.getDisplayContent(mDisplayId)
.mAppTransition.overrideInPlaceAppTransition(packageName, anim);
}
}
/**
* Get Pending App transition of display.
*
* @return The pending app transition of the display.
*/
public @TransitionType int getPendingAppTransition() {
synchronized (mGlobalLock) {
return mRoot.getDisplayContent(mDisplayId).mAppTransition.getAppTransition();
}
}
/**
* Check if pending app transition is for activity / task launch.
*/
public boolean isNextTransitionForward() {
final int transit = getPendingAppTransition();
return transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
|| transit == TRANSIT_TASK_TO_FRONT;
}
@Override
public String toString() {
return "{DisplayWindowController displayId=" + mDisplayId + "}";
}
}