747 lines
28 KiB
Java
747 lines
28 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2019 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 android.view;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.app.WindowConfiguration;
|
||
|
import android.content.res.Configuration;
|
||
|
import android.graphics.PixelFormat;
|
||
|
import android.graphics.Rect;
|
||
|
import android.graphics.Region;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.IBinder;
|
||
|
import android.os.RemoteCallback;
|
||
|
import android.os.RemoteException;
|
||
|
import android.util.Log;
|
||
|
import android.util.MergedConfiguration;
|
||
|
import android.view.View.FocusDirection;
|
||
|
import android.view.WindowInsets.Type.InsetsType;
|
||
|
import android.window.ClientWindowFrames;
|
||
|
import android.window.InputTransferToken;
|
||
|
import android.window.OnBackInvokedCallbackInfo;
|
||
|
|
||
|
import java.util.HashMap;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
|
||
|
/**
|
||
|
* A simplistic implementation of IWindowSession. Rather than managing Surfaces
|
||
|
* as children of the display, it manages Surfaces as children of a given root.
|
||
|
*
|
||
|
* By parcelling the root surface, the app can offer another app content for embedding.
|
||
|
* @hide
|
||
|
*/
|
||
|
public class WindowlessWindowManager implements IWindowSession {
|
||
|
private final static String TAG = "WindowlessWindowManager";
|
||
|
|
||
|
private class State {
|
||
|
SurfaceControl mSurfaceControl;
|
||
|
final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
|
||
|
final WindowManager.LayoutParams mLastReportedParams = new WindowManager.LayoutParams();
|
||
|
int mDisplayId;
|
||
|
IBinder mInputChannelToken;
|
||
|
Region mInputRegion;
|
||
|
IWindow mClient;
|
||
|
SurfaceControl mLeash;
|
||
|
Rect mFrame;
|
||
|
Rect mAttachedFrame;
|
||
|
InputTransferToken mInputTransferToken;
|
||
|
|
||
|
State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, IWindow client,
|
||
|
SurfaceControl leash, Rect frame) {
|
||
|
mSurfaceControl = sc;
|
||
|
mParams.copyFrom(p);
|
||
|
mDisplayId = displayId;
|
||
|
mClient = client;
|
||
|
mLeash = leash;
|
||
|
mFrame = frame;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Used to store SurfaceControl we've built for clients to
|
||
|
* reconfigure them if relayout is called.
|
||
|
*/
|
||
|
final HashMap<IBinder, State> mStateForWindow = new HashMap<IBinder, State>();
|
||
|
|
||
|
public interface ResizeCompleteCallback {
|
||
|
public void finished(SurfaceControl.Transaction completion);
|
||
|
}
|
||
|
|
||
|
final HashMap<IBinder, ResizeCompleteCallback> mResizeCompletionForWindow =
|
||
|
new HashMap<IBinder, ResizeCompleteCallback>();
|
||
|
|
||
|
private final SurfaceSession mSurfaceSession = new SurfaceSession();
|
||
|
protected final SurfaceControl mRootSurface;
|
||
|
private final Configuration mConfiguration;
|
||
|
private final IWindowSession mRealWm;
|
||
|
final InputTransferToken mHostInputTransferToken;
|
||
|
private final InputTransferToken mInputTransferToken = new InputTransferToken();
|
||
|
private InsetsState mInsetsState;
|
||
|
private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
|
||
|
private final MergedConfiguration mTmpConfig = new MergedConfiguration();
|
||
|
private final WindowlessWindowLayout mLayout = new WindowlessWindowLayout();
|
||
|
|
||
|
private ISurfaceControlViewHostParent mParentInterface;
|
||
|
|
||
|
public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
|
||
|
InputTransferToken hostInputTransferToken) {
|
||
|
mRootSurface = rootSurface;
|
||
|
mConfiguration = new Configuration(c);
|
||
|
mRealWm = WindowManagerGlobal.getWindowSession();
|
||
|
mHostInputTransferToken = hostInputTransferToken;
|
||
|
}
|
||
|
|
||
|
public void setConfiguration(Configuration configuration) {
|
||
|
mConfiguration.setTo(configuration);
|
||
|
}
|
||
|
|
||
|
InputTransferToken getInputTransferToken(IBinder window) {
|
||
|
synchronized (this) {
|
||
|
// This can only happen if someone requested the focusGrantToken before setView was
|
||
|
// called for the SCVH. In that case, use the root focusGrantToken since this will be
|
||
|
// the same token sent to WMS for the root window once setView is called.
|
||
|
if (mStateForWindow.isEmpty()) {
|
||
|
return mInputTransferToken;
|
||
|
}
|
||
|
State state = mStateForWindow.get(window);
|
||
|
if (state != null) {
|
||
|
return state.mInputTransferToken;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Log.w(TAG, "Failed to get focusGrantToken. Returning null token");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility API.
|
||
|
*/
|
||
|
void setCompletionCallback(IBinder window, ResizeCompleteCallback callback) {
|
||
|
if (mResizeCompletionForWindow.get(window) != null) {
|
||
|
Log.w(TAG, "Unsupported overlapping resizes");
|
||
|
}
|
||
|
mResizeCompletionForWindow.put(window, callback);
|
||
|
}
|
||
|
|
||
|
protected void setTouchRegion(IBinder window, @Nullable Region region) {
|
||
|
State state;
|
||
|
synchronized (this) {
|
||
|
// Do everything while locked so that we synchronize with relayout. This should be a
|
||
|
// very infrequent operation.
|
||
|
state = mStateForWindow.get(window);
|
||
|
if (state == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (Objects.equals(region, state.mInputRegion)) {
|
||
|
return;
|
||
|
}
|
||
|
state.mInputRegion = region != null ? new Region(region) : null;
|
||
|
if (state.mInputChannelToken != null) {
|
||
|
try {
|
||
|
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
|
||
|
state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags,
|
||
|
state.mParams.inputFeatures, state.mInputRegion);
|
||
|
} catch (RemoteException e) {
|
||
|
Log.e(TAG, "Failed to update surface input channel: ", e);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
|
||
|
// If this is the first window, the state map is empty and the parent surface is the
|
||
|
// root. Otherwise, the parent surface is in the state map.
|
||
|
synchronized (this) {
|
||
|
if (mStateForWindow.isEmpty()) {
|
||
|
return mRootSurface;
|
||
|
}
|
||
|
return mStateForWindow.get(attrs.token).mLeash;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* IWindowSession implementation.
|
||
|
*/
|
||
|
@Override
|
||
|
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
|
||
|
int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes,
|
||
|
InputChannel outInputChannel, InsetsState outInsetsState,
|
||
|
InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
|
||
|
float[] outSizeCompatScale) {
|
||
|
final SurfaceControl leash = new SurfaceControl.Builder(mSurfaceSession)
|
||
|
.setName(attrs.getTitle().toString() + "Leash")
|
||
|
.setCallsite("WindowlessWindowManager.addToDisplay")
|
||
|
.setParent(getParentSurface(window, attrs))
|
||
|
.build();
|
||
|
|
||
|
final SurfaceControl sc = new SurfaceControl.Builder(mSurfaceSession)
|
||
|
.setFormat(attrs.format)
|
||
|
.setBLASTLayer()
|
||
|
.setName(attrs.getTitle().toString())
|
||
|
.setCallsite("WindowlessWindowManager.addToDisplay")
|
||
|
.setHidden(false)
|
||
|
.setParent(leash)
|
||
|
.build();
|
||
|
|
||
|
final State state = new State(sc, attrs, displayId, window, leash, /* frame= */ new Rect());
|
||
|
synchronized (this) {
|
||
|
State parentState = mStateForWindow.get(attrs.token);
|
||
|
if (parentState != null) {
|
||
|
state.mAttachedFrame = parentState.mFrame;
|
||
|
}
|
||
|
|
||
|
// Give the first window the mFocusGrantToken since that's the token the host can use
|
||
|
// to give focus to the embedded.
|
||
|
if (mStateForWindow.isEmpty()) {
|
||
|
state.mInputTransferToken = mInputTransferToken;
|
||
|
} else {
|
||
|
state.mInputTransferToken = new InputTransferToken();
|
||
|
}
|
||
|
|
||
|
mStateForWindow.put(window.asBinder(), state);
|
||
|
}
|
||
|
|
||
|
if (state.mAttachedFrame == null) {
|
||
|
outAttachedFrame.set(0, 0, -1, -1);
|
||
|
} else {
|
||
|
outAttachedFrame.set(state.mAttachedFrame);
|
||
|
}
|
||
|
outSizeCompatScale[0] = 1f;
|
||
|
|
||
|
if (((attrs.inputFeatures &
|
||
|
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
|
||
|
try {
|
||
|
if (mRealWm instanceof IWindowSession.Stub) {
|
||
|
mRealWm.grantInputChannel(displayId,
|
||
|
new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
|
||
|
window.asBinder(), mHostInputTransferToken, attrs.flags,
|
||
|
attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
|
||
|
state.mInputTransferToken, attrs.getTitle().toString(),
|
||
|
outInputChannel);
|
||
|
} else {
|
||
|
mRealWm.grantInputChannel(displayId, sc, window.asBinder(),
|
||
|
mHostInputTransferToken, attrs.flags, attrs.privateFlags,
|
||
|
attrs.inputFeatures, attrs.type, attrs.token, state.mInputTransferToken,
|
||
|
attrs.getTitle().toString(), outInputChannel);
|
||
|
}
|
||
|
state.mInputChannelToken =
|
||
|
outInputChannel != null ? outInputChannel.getToken() : null;
|
||
|
} catch (RemoteException e) {
|
||
|
Log.e(TAG, "Failed to grant input to surface: ", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
|
||
|
|
||
|
sendLayoutParamsToParent();
|
||
|
// Include whether the window is in touch mode.
|
||
|
return isInTouchModeInternal(displayId) ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE
|
||
|
: res;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* IWindowSession implementation. Currently this class doesn't need to support for multi-user.
|
||
|
*/
|
||
|
@Override
|
||
|
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
|
||
|
int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
|
||
|
InputChannel outInputChannel, InsetsState outInsetsState,
|
||
|
InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
|
||
|
float[] outSizeCompatScale) {
|
||
|
return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibleTypes,
|
||
|
outInputChannel, outInsetsState, outActiveControls, outAttachedFrame,
|
||
|
outSizeCompatScale);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int addToDisplayWithoutInputChannel(android.view.IWindow window,
|
||
|
android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId,
|
||
|
android.view.InsetsState insetsState, Rect outAttachedFrame,
|
||
|
float[] outSizeCompatScale) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void remove(IBinder clientToken) throws RemoteException {
|
||
|
mRealWm.remove(clientToken);
|
||
|
State state;
|
||
|
synchronized (this) {
|
||
|
state = mStateForWindow.remove(clientToken);
|
||
|
}
|
||
|
if (state == null) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"Invalid window token (never added or removed already)");
|
||
|
}
|
||
|
removeSurface(state.mSurfaceControl);
|
||
|
removeSurface(state.mLeash);
|
||
|
}
|
||
|
|
||
|
/** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
|
||
|
protected void removeSurface(SurfaceControl sc) {
|
||
|
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
|
||
|
t.remove(sc).apply();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private boolean isOpaque(WindowManager.LayoutParams attrs) {
|
||
|
if (attrs.surfaceInsets != null && attrs.surfaceInsets.left != 0 ||
|
||
|
attrs.surfaceInsets.top != 0 || attrs.surfaceInsets.right != 0 ||
|
||
|
attrs.surfaceInsets.bottom != 0) {
|
||
|
return false;
|
||
|
}
|
||
|
return !PixelFormat.formatHasAlpha(attrs.format);
|
||
|
}
|
||
|
|
||
|
private boolean isInTouchModeInternal(int displayId) {
|
||
|
try {
|
||
|
return WindowManagerGlobal.getWindowManagerService().isInTouchMode(displayId);
|
||
|
} catch (RemoteException e) {
|
||
|
Log.e(TAG, "Unable to check if the window is in touch mode", e);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/** Access to package members for SystemWindow leashing
|
||
|
* @hide
|
||
|
*/
|
||
|
protected IBinder getWindowBinder(View rootView) {
|
||
|
final ViewRootImpl root = rootView.getViewRootImpl();
|
||
|
if (root == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return root.mWindow.asBinder();
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@Nullable
|
||
|
protected SurfaceControl getSurfaceControl(View rootView) {
|
||
|
final ViewRootImpl root = rootView.getViewRootImpl();
|
||
|
if (root == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return getSurfaceControl(root.mWindow);
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@Nullable
|
||
|
protected SurfaceControl getSurfaceControl(IWindow window) {
|
||
|
final State s = mStateForWindow.get(window.asBinder());
|
||
|
if (s == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return s.mSurfaceControl;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int relayoutLegacy(IWindow window, WindowManager.LayoutParams inAttrs,
|
||
|
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
|
||
|
int lastSyncSeqId, ClientWindowFrames outFrames,
|
||
|
MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
|
||
|
InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
|
||
|
Bundle outSyncSeqIdBundle) {
|
||
|
return relayoutInner(window, inAttrs, requestedWidth, requestedHeight, viewFlags, flags,
|
||
|
seq, lastSyncSeqId, outFrames, outMergedConfiguration, outSurfaceControl,
|
||
|
outInsetsState, outActiveControls);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int relayout(IWindow window, WindowManager.LayoutParams inAttrs,
|
||
|
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
|
||
|
int lastSyncSeqId, WindowRelayoutResult outRelayoutResult) {
|
||
|
final ClientWindowFrames outFrames;
|
||
|
final MergedConfiguration outMergedConfiguration;
|
||
|
final SurfaceControl outSurfaceControl;
|
||
|
final InsetsState outInsetsState;
|
||
|
final InsetsSourceControl.Array outActiveControls;
|
||
|
if (outRelayoutResult != null) {
|
||
|
outFrames = outRelayoutResult.frames;
|
||
|
outMergedConfiguration = outRelayoutResult.mergedConfiguration;
|
||
|
outSurfaceControl = outRelayoutResult.surfaceControl;
|
||
|
outInsetsState = outRelayoutResult.insetsState;
|
||
|
outActiveControls = outRelayoutResult.activeControls;
|
||
|
} else {
|
||
|
outFrames = null;
|
||
|
outMergedConfiguration = null;
|
||
|
outSurfaceControl = null;
|
||
|
outInsetsState = null;
|
||
|
outActiveControls = null;
|
||
|
}
|
||
|
return relayoutInner(window, inAttrs, requestedWidth, requestedHeight, viewFlags, flags,
|
||
|
seq, lastSyncSeqId, outFrames, outMergedConfiguration, outSurfaceControl,
|
||
|
outInsetsState, outActiveControls);
|
||
|
}
|
||
|
|
||
|
private int relayoutInner(IWindow window, WindowManager.LayoutParams inAttrs,
|
||
|
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
|
||
|
int lastSyncSeqId, ClientWindowFrames outFrames,
|
||
|
MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
|
||
|
InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls) {
|
||
|
final State state;
|
||
|
synchronized (this) {
|
||
|
state = mStateForWindow.get(window.asBinder());
|
||
|
}
|
||
|
if (state == null) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"Invalid window token (never added or removed already)");
|
||
|
}
|
||
|
SurfaceControl sc = state.mSurfaceControl;
|
||
|
SurfaceControl leash = state.mLeash;
|
||
|
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||
|
|
||
|
int attrChanges = 0;
|
||
|
if (inAttrs != null) {
|
||
|
attrChanges = state.mParams.copyFrom(inAttrs);
|
||
|
}
|
||
|
WindowManager.LayoutParams attrs = state.mParams;
|
||
|
|
||
|
ClientWindowFrames frames = new ClientWindowFrames();
|
||
|
frames.attachedFrame = state.mAttachedFrame;
|
||
|
|
||
|
mLayout.computeFrames(attrs, null, null, null, WindowConfiguration.WINDOWING_MODE_UNDEFINED,
|
||
|
requestedWidth, requestedHeight, 0, 0,
|
||
|
frames);
|
||
|
|
||
|
state.mFrame.set(frames.frame);
|
||
|
if (outFrames != null) {
|
||
|
outFrames.frame.set(frames.frame);
|
||
|
outFrames.parentFrame.set(frames.parentFrame);
|
||
|
outFrames.displayFrame.set(frames.displayFrame);
|
||
|
}
|
||
|
|
||
|
t.setPosition(leash, frames.frame.left, frames.frame.top);
|
||
|
|
||
|
if (viewFlags == View.VISIBLE) {
|
||
|
// TODO(b/262892794) ViewRootImpl modifies the app's rendering SurfaceControl
|
||
|
// opaqueness. We shouldn't need to modify opaqueness for this SurfaceControl here or
|
||
|
// in the real WindowManager.
|
||
|
t.setOpaque(sc, isOpaque(attrs)).show(leash).apply();
|
||
|
if (outSurfaceControl != null) {
|
||
|
outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
|
||
|
}
|
||
|
} else {
|
||
|
t.hide(leash).apply();
|
||
|
if (outSurfaceControl != null) {
|
||
|
outSurfaceControl.release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (outMergedConfiguration != null) {
|
||
|
outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
|
||
|
}
|
||
|
|
||
|
final int inputChangeMask = WindowManager.LayoutParams.FLAGS_CHANGED
|
||
|
| WindowManager.LayoutParams.INPUT_FEATURES_CHANGED;
|
||
|
if ((attrChanges & inputChangeMask) != 0 && state.mInputChannelToken != null) {
|
||
|
try {
|
||
|
if (mRealWm instanceof IWindowSession.Stub) {
|
||
|
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
|
||
|
new SurfaceControl(sc, "WindowlessWindowManager.relayout"),
|
||
|
attrs.flags, attrs.privateFlags, attrs.inputFeatures,
|
||
|
state.mInputRegion);
|
||
|
} else {
|
||
|
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
|
||
|
attrs.flags, attrs.privateFlags, attrs.inputFeatures,
|
||
|
state.mInputRegion);
|
||
|
}
|
||
|
} catch (RemoteException e) {
|
||
|
Log.e(TAG, "Failed to update surface input channel: ", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (outInsetsState != null && mInsetsState != null) {
|
||
|
outInsetsState.set(mInsetsState);
|
||
|
}
|
||
|
|
||
|
sendLayoutParamsToParent();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void relayoutAsync(IWindow window, WindowManager.LayoutParams inAttrs,
|
||
|
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
|
||
|
int lastSyncSeqId) {
|
||
|
relayoutInner(window, inAttrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
|
||
|
lastSyncSeqId, null /* outFrames */, null /* outMergedConfiguration */,
|
||
|
null /* outSurfaceControl */, null /* outInsetsState */,
|
||
|
null /* outActiveControls */);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean outOfMemory(android.view.IWindow window) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setInsets(android.view.IWindow window, int touchableInsets,
|
||
|
android.graphics.Rect contentInsets, android.graphics.Rect visibleInsets,
|
||
|
android.graphics.Region touchableRegion) {
|
||
|
setTouchRegion(window.asBinder(), touchableRegion);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void clearTouchableRegion(android.view.IWindow window) {
|
||
|
setTouchRegion(window.asBinder(), null);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void finishDrawing(android.view.IWindow window,
|
||
|
android.view.SurfaceControl.Transaction postDrawTransaction, int seqId) {
|
||
|
synchronized (this) {
|
||
|
final ResizeCompleteCallback c =
|
||
|
mResizeCompletionForWindow.get(window.asBinder());
|
||
|
if (c == null) {
|
||
|
// No one wanted the callback, but it wasn't necessarily unexpected.
|
||
|
postDrawTransaction.apply();
|
||
|
return;
|
||
|
}
|
||
|
c.finished(postDrawTransaction);
|
||
|
mResizeCompletionForWindow.remove(window.asBinder());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void performHapticFeedbackAsync(int effectId, boolean always, boolean fromIme) {
|
||
|
performHapticFeedback(effectId, always, fromIme);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public android.os.IBinder performDrag(android.view.IWindow window, int flags,
|
||
|
android.view.SurfaceControl surface, int touchSource, int touchDeviceId,
|
||
|
int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
|
||
|
android.content.ClipData data) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void reportDropResult(android.view.IWindow window, boolean consumed) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void cancelDragAndDrop(android.os.IBinder dragToken, boolean skipAnimation) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void dragRecipientEntered(android.view.IWindow window) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void dragRecipientExited(android.view.IWindow window) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setWallpaperPosition(android.os.IBinder windowToken, float x, float y,
|
||
|
float xstep, float ystep) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setWallpaperZoomOut(android.os.IBinder windowToken, float zoom) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setShouldZoomOutWallpaper(android.os.IBinder windowToken, boolean shouldZoom) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void wallpaperOffsetsComplete(android.os.IBinder window) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setWallpaperDisplayOffset(android.os.IBinder windowToken, int x, int y) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void sendWallpaperCommand(android.os.IBinder window,
|
||
|
java.lang.String action, int x, int y, int z, android.os.Bundle extras, boolean sync) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void wallpaperCommandComplete(android.os.IBinder window, android.os.Bundle result) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onRectangleOnScreenRequested(android.os.IBinder token,
|
||
|
android.graphics.Rect rectangle) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public android.view.IWindowId getWindowId(android.os.IBinder window) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void pokeDrawLock(android.os.IBinder window) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean startMovingTask(android.view.IWindow window, float startX, float startY) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void finishMovingTask(android.view.IWindow window) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void updateTapExcludeRegion(android.view.IWindow window,
|
||
|
android.graphics.Region region) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void updateRequestedVisibleTypes(IWindow window,
|
||
|
@InsetsType int requestedVisibleTypes) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void reportSystemGestureExclusionChanged(android.view.IWindow window,
|
||
|
List<Rect> exclusionRects) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) {}
|
||
|
|
||
|
@Override
|
||
|
public void reportKeepClearAreasChanged(
|
||
|
android.view.IWindow window,
|
||
|
List<Rect> restrictedRects,
|
||
|
List<Rect> unrestrictedRects) {}
|
||
|
|
||
|
@Override
|
||
|
public void grantInputChannel(int displayId, SurfaceControl surface, IBinder clientToken,
|
||
|
InputTransferToken hostInputToken, int flags, int privateFlags, int inputFeatures,
|
||
|
int type, IBinder windowToken, InputTransferToken embeddedInputTransferToken,
|
||
|
String inputHandleName, InputChannel outInputChannel) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
|
||
|
int flags, int privateFlags, int inputFeatures, Region region) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public android.os.IBinder asBinder() {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void grantEmbeddedWindowFocus(IWindow callingWindow, InputTransferToken targetInputToken,
|
||
|
boolean grantFocus) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
|
||
|
RemoteCallback callback) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setOnBackInvokedCallbackInfo(IWindow iWindow,
|
||
|
OnBackInvokedCallbackInfo callbackInfo) throws RemoteException { }
|
||
|
|
||
|
@Override
|
||
|
public boolean dropForAccessibility(IWindow window, int x, int y) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public void setInsetsState(InsetsState state) {
|
||
|
mInsetsState = state;
|
||
|
for (State s : mStateForWindow.values()) {
|
||
|
try {
|
||
|
mTmpFrames.frame.set(0, 0, s.mParams.width, s.mParams.height);
|
||
|
mTmpFrames.displayFrame.set(mTmpFrames.frame);
|
||
|
mTmpConfig.setConfiguration(mConfiguration, mConfiguration);
|
||
|
s.mClient.resized(mTmpFrames, false /* reportDraw */, mTmpConfig, state,
|
||
|
false /* forceLayout */, false /* alwaysConsumeSystemBars */, s.mDisplayId,
|
||
|
Integer.MAX_VALUE, false /* dragResizing */, null /* activityWindowInfo */);
|
||
|
} catch (RemoteException e) {
|
||
|
// Too bad
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean cancelDraw(IWindow window) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
|
||
|
Log.e(TAG, "Received request to moveFocusToAdjacentWindow on"
|
||
|
+ " WindowlessWindowManager. We shouldn't get here!");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
|
||
|
IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
|
||
|
IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
|
||
|
// If the parent interface has changed, it needs to clear the last reported params so it
|
||
|
// will update the new interface with the params.
|
||
|
if (oldInterface != newInterface) {
|
||
|
clearLastReportedParams();
|
||
|
}
|
||
|
mParentInterface = parentInterface;
|
||
|
sendLayoutParamsToParent();
|
||
|
}
|
||
|
|
||
|
private void clearLastReportedParams() {
|
||
|
WindowManager.LayoutParams emptyParam = new WindowManager.LayoutParams();
|
||
|
for (State windowInfo : mStateForWindow.values()) {
|
||
|
windowInfo.mLastReportedParams.copyFrom(emptyParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void sendLayoutParamsToParent() {
|
||
|
if (mParentInterface == null) {
|
||
|
return;
|
||
|
}
|
||
|
WindowManager.LayoutParams[] params =
|
||
|
new WindowManager.LayoutParams[mStateForWindow.size()];
|
||
|
int index = 0;
|
||
|
boolean hasChanges = false;
|
||
|
for (State windowInfo : mStateForWindow.values()) {
|
||
|
int changes = windowInfo.mLastReportedParams.copyFrom(windowInfo.mParams);
|
||
|
hasChanges |= (changes != 0);
|
||
|
params[index++] = windowInfo.mParams;
|
||
|
}
|
||
|
|
||
|
if (hasChanges) {
|
||
|
try {
|
||
|
mParentInterface.updateParams(params);
|
||
|
} catch (RemoteException e) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
boolean forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
|
||
|
if (mParentInterface == null) {
|
||
|
return false;
|
||
|
}
|
||
|
try {
|
||
|
mParentInterface.forwardBackKeyToParent(keyEvent);
|
||
|
} catch (RemoteException e) {
|
||
|
Log.e(TAG, "Failed to forward back key To Parent: ", e);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|