605 lines
24 KiB
Java
605 lines
24 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.FlaggedApi;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.TestApi;
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.PixelFormat;
|
|
import android.graphics.Rect;
|
|
import android.os.IBinder;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.os.RemoteException;
|
|
import android.util.Log;
|
|
import android.view.accessibility.IAccessibilityEmbeddedConnection;
|
|
import android.window.ISurfaceSyncGroup;
|
|
import android.window.InputTransferToken;
|
|
import android.window.WindowTokenClient;
|
|
|
|
import com.android.window.flags.Flags;
|
|
|
|
import dalvik.system.CloseGuard;
|
|
|
|
import java.util.Objects;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
/**
|
|
* Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
|
|
* will render in to a root SurfaceControl, and receive input based on the SurfaceControl's
|
|
* placement on-screen. The primary usage of this class is to embed a View hierarchy from
|
|
* one process in to another. After the SurfaceControlViewHost has been set up in the embedded
|
|
* content provider, we can send the {@link SurfaceControlViewHost.SurfacePackage}
|
|
* to the host process. The host process can then attach the hierarchy to a SurfaceView within
|
|
* its own by calling
|
|
* {@link SurfaceView#setChildSurfacePackage}.
|
|
*/
|
|
public class SurfaceControlViewHost {
|
|
private final static String TAG = "SurfaceControlViewHost";
|
|
private final ViewRootImpl mViewRoot;
|
|
private final CloseGuard mCloseGuard = CloseGuard.get();
|
|
private final WindowlessWindowManager mWm;
|
|
|
|
private SurfaceControl mSurfaceControl;
|
|
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
|
|
private boolean mReleased = false;
|
|
|
|
private final class ISurfaceControlViewHostImpl extends ISurfaceControlViewHost.Stub {
|
|
@Override
|
|
public void onConfigurationChanged(Configuration configuration) {
|
|
if (mViewRoot == null) {
|
|
return;
|
|
}
|
|
mViewRoot.mHandler.post(() -> {
|
|
mWm.setConfiguration(configuration);
|
|
if (mViewRoot != null) {
|
|
mViewRoot.forceWmRelayout();
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onDispatchDetachedFromWindow() {
|
|
if (mViewRoot == null) {
|
|
return;
|
|
}
|
|
mViewRoot.mHandler.post(() -> {
|
|
release();
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onInsetsChanged(InsetsState state, Rect frame) {
|
|
if (mViewRoot != null) {
|
|
mViewRoot.mHandler.post(() -> {
|
|
mViewRoot.setOverrideInsetsFrame(frame);
|
|
});
|
|
}
|
|
mWm.setInsetsState(state);
|
|
}
|
|
|
|
@Override
|
|
public ISurfaceSyncGroup getSurfaceSyncGroup() {
|
|
CompletableFuture<ISurfaceSyncGroup> surfaceSyncGroup = new CompletableFuture<>();
|
|
// If the call came from in process and it's already running on the UI thread, return
|
|
// results immediately instead of posting to the main thread. If we post to the main
|
|
// thread, it will block itself and the return value will always be null.
|
|
if (Thread.currentThread() == mViewRoot.mThread) {
|
|
return mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup;
|
|
} else {
|
|
mViewRoot.mHandler.post(
|
|
() -> surfaceSyncGroup.complete(
|
|
mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup));
|
|
}
|
|
try {
|
|
return surfaceSyncGroup.get(1, TimeUnit.SECONDS);
|
|
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
Log.e(TAG, "Failed to get SurfaceSyncGroup for SCVH", e);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void attachParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
|
|
mViewRoot.mHandler.post(() -> mWm.setParentInterface(parentInterface));
|
|
}
|
|
}
|
|
|
|
private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl();
|
|
|
|
private ViewRootImpl.ConfigChangedCallback mConfigChangedCallback;
|
|
|
|
/**
|
|
* Package encapsulating a Surface hierarchy which contains interactive view
|
|
* elements. It's expected to get this object from
|
|
* {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within
|
|
* a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}.
|
|
*
|
|
* Note that each {@link SurfacePackage} must be released by calling
|
|
* {@link SurfacePackage#release}. However, if you use the recommended flow,
|
|
* the framework will automatically handle the lifetime for you.
|
|
*
|
|
* 1. When sending the package to the remote process, return it from an AIDL method
|
|
* or manually use FLAG_WRITE_RETURN_VALUE in writeToParcel. This will automatically
|
|
* release the package in the local process.
|
|
* 2. In the remote process, consume the package using SurfaceView. This way the
|
|
* SurfaceView will take over the lifetime and call {@link SurfacePackage#release}
|
|
* for the user.
|
|
*
|
|
* One final note: The {@link SurfacePackage} lifetime is totally de-coupled
|
|
* from the lifetime of the underlying {@link SurfaceControlViewHost}. Regardless
|
|
* of the lifetime of the package the user should still call
|
|
* {@link SurfaceControlViewHost#release} when finished.
|
|
*/
|
|
public static final class SurfacePackage implements Parcelable {
|
|
private SurfaceControl mSurfaceControl;
|
|
private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
|
|
private final InputTransferToken mInputTransferToken;
|
|
@NonNull
|
|
private final ISurfaceControlViewHost mRemoteInterface;
|
|
|
|
SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection,
|
|
InputTransferToken inputTransferToken,
|
|
@NonNull ISurfaceControlViewHost ri) {
|
|
mSurfaceControl = sc;
|
|
mAccessibilityEmbeddedConnection = connection;
|
|
mInputTransferToken = inputTransferToken;
|
|
mRemoteInterface = ri;
|
|
}
|
|
|
|
/**
|
|
* Constructs a copy of {@code SurfacePackage} with an independent lifetime.
|
|
*
|
|
* The caller can use this to create an independent copy in situations where ownership of
|
|
* the {@code SurfacePackage} would be transferred elsewhere, such as attaching to a
|
|
* {@code SurfaceView}, returning as {@code Binder} result value, etc. The caller is
|
|
* responsible for releasing this copy when its done.
|
|
*
|
|
* @param other {@code SurfacePackage} to create a copy of.
|
|
*/
|
|
public SurfacePackage(@NonNull SurfacePackage other) {
|
|
SurfaceControl otherSurfaceControl = other.mSurfaceControl;
|
|
if (otherSurfaceControl != null && otherSurfaceControl.isValid()) {
|
|
mSurfaceControl = new SurfaceControl(otherSurfaceControl, "SurfacePackage");
|
|
}
|
|
mAccessibilityEmbeddedConnection = other.mAccessibilityEmbeddedConnection;
|
|
mInputTransferToken = other.mInputTransferToken;
|
|
mRemoteInterface = other.mRemoteInterface;
|
|
}
|
|
|
|
private SurfacePackage(Parcel in) {
|
|
mSurfaceControl = new SurfaceControl();
|
|
mSurfaceControl.readFromParcel(in);
|
|
mSurfaceControl.setUnreleasedWarningCallSite("SurfacePackage(Parcel)");
|
|
mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
|
|
in.readStrongBinder());
|
|
mInputTransferToken = InputTransferToken.CREATOR.createFromParcel(in);
|
|
mRemoteInterface = ISurfaceControlViewHost.Stub.asInterface(in.readStrongBinder());
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link android.view.SurfaceControl} associated with this SurfacePackage for
|
|
* cases where more control is required.
|
|
*
|
|
* @return the SurfaceControl associated with this SurfacePackage and its containing
|
|
* SurfaceControlViewHost
|
|
*/
|
|
public @NonNull SurfaceControl getSurfaceControl() {
|
|
return mSurfaceControl;
|
|
}
|
|
|
|
/**
|
|
* Gets an accessibility embedded connection interface for this SurfaceControlViewHost.
|
|
*
|
|
* @return {@link IAccessibilityEmbeddedConnection} interface.
|
|
* @hide
|
|
*/
|
|
public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
|
|
return mAccessibilityEmbeddedConnection;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@NonNull
|
|
public ISurfaceControlViewHost getRemoteInterface() {
|
|
return mRemoteInterface;
|
|
}
|
|
|
|
/**
|
|
* Forward a configuration to the remote SurfaceControlViewHost.
|
|
* This will cause View#onConfigurationChanged to be invoked on the remote
|
|
* end. This does not automatically cause the SurfaceControlViewHost
|
|
* to be resized. The root View of a SurfaceControlViewHost
|
|
* is more akin to a PopupWindow in that the size is user specified
|
|
* independent of configuration width and height.
|
|
*
|
|
* In order to receive the configuration change via
|
|
* {@link View#onConfigurationChanged}, the context used with the
|
|
* SurfaceControlViewHost and it's embedded view hierarchy must
|
|
* be a WindowContext obtained from {@link Context#createWindowContext}.
|
|
*
|
|
* If a regular service context is used, then your embedded view hierarchy
|
|
* will always perceive the global configuration.
|
|
*
|
|
* @param c The configuration to forward
|
|
*/
|
|
public void notifyConfigurationChanged(@NonNull Configuration c) {
|
|
try {
|
|
getRemoteInterface().onConfigurationChanged(c);
|
|
} catch (RemoteException e) {
|
|
e.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tear down the remote SurfaceControlViewHost and cause
|
|
* View#onDetachedFromWindow to be invoked on the other side.
|
|
*/
|
|
public void notifyDetachedFromWindow() {
|
|
try {
|
|
getRemoteInterface().onDispatchDetachedFromWindow();
|
|
} catch (RemoteException e) {
|
|
e.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(@NonNull Parcel out, int flags) {
|
|
mSurfaceControl.writeToParcel(out, flags);
|
|
out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
|
|
mInputTransferToken.writeToParcel(out, flags);
|
|
out.writeStrongBinder(mRemoteInterface.asBinder());
|
|
}
|
|
|
|
/**
|
|
* Release the {@link SurfaceControl} associated with this package.
|
|
* It's not necessary to call this if you pass the package to
|
|
* {@link SurfaceView#setChildSurfacePackage} as {@link SurfaceView} will
|
|
* take ownership in that case.
|
|
*/
|
|
public void release() {
|
|
if (mSurfaceControl != null) {
|
|
mSurfaceControl.release();
|
|
}
|
|
mSurfaceControl = null;
|
|
}
|
|
|
|
/**
|
|
* Gets an {@link InputTransferToken} which can be used to request focus on the embedded
|
|
* surface or to transfer touch gesture to the embedded surface.
|
|
*
|
|
* @return the InputTransferToken associated with {@link SurfacePackage} or {@code null} if
|
|
* the embedded hasn't set up its view or doesn't have input.
|
|
* @see WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
|
|
*/
|
|
@Nullable
|
|
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
|
|
public InputTransferToken getInputTransferToken() {
|
|
return mInputTransferToken;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "{inputTransferToken=" + getInputTransferToken() + " remoteInterface="
|
|
+ getRemoteInterface() + "}";
|
|
}
|
|
|
|
public static final @NonNull Creator<SurfacePackage> CREATOR
|
|
= new Creator<SurfacePackage>() {
|
|
public SurfacePackage createFromParcel(Parcel in) {
|
|
return new SurfacePackage(in);
|
|
}
|
|
public SurfacePackage[] newArray(int size) {
|
|
return new SurfacePackage[size];
|
|
}
|
|
};
|
|
}
|
|
|
|
/** @hide */
|
|
public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
|
|
@NonNull WindowlessWindowManager wwm, @NonNull String callsite) {
|
|
mSurfaceControl = wwm.mRootSurface;
|
|
mWm = wwm;
|
|
mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout());
|
|
mCloseGuard.openWithCallSite("release", callsite);
|
|
setConfigCallback(c, d);
|
|
|
|
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
|
|
|
|
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
|
|
}
|
|
|
|
/**
|
|
* Construct a new SurfaceControlViewHost. The root Surface will be
|
|
* allocated internally and is accessible via getSurfacePackage().
|
|
*
|
|
* The {@param hostToken} parameter, primarily used for ANR reporting,
|
|
* must be obtained from whomever will be hosting the embedded hierarchy.
|
|
* It's accessible from {@link SurfaceView#getHostToken}.
|
|
*
|
|
* @param context The Context object for your activity or application.
|
|
* @param display The Display the hierarchy will be placed on.
|
|
* @param hostToken The host token, as discussed above.
|
|
*/
|
|
public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
|
|
@Nullable IBinder hostToken) {
|
|
this(context, display, hostToken == null ? null : new InputTransferToken(hostToken),
|
|
"untracked");
|
|
|
|
}
|
|
|
|
/**
|
|
* Construct a new SurfaceControlViewHost. The root Surface will be
|
|
* allocated internally and is accessible via getSurfacePackage().
|
|
* <p>
|
|
* The hostInputTransferToken parameter allows the host and embedded to be associated with
|
|
* each other to allow transferring touch gesture and focus. This is also used for ANR
|
|
* reporting. It's accessible from {@link AttachedSurfaceControl#getInputTransferToken()}.
|
|
*
|
|
* @param context The Context object for your activity or application.
|
|
* @param display The Display the hierarchy will be placed on.
|
|
* @param hostInputTransferToken The host input transfer token, as discussed above.
|
|
*/
|
|
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
|
|
public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
|
|
@Nullable InputTransferToken hostInputTransferToken) {
|
|
this(context, display, hostInputTransferToken, "untracked");
|
|
}
|
|
|
|
/**
|
|
* Construct a new SurfaceControlViewHost. The root Surface will be
|
|
* allocated internally and is accessible via getSurfacePackage().
|
|
*
|
|
* The {@param hostToken} parameter, primarily used for ANR reporting,
|
|
* must be obtained from whomever will be hosting the embedded hierarchy.
|
|
* It's accessible from {@link SurfaceView#getHostToken}.
|
|
*
|
|
* @param context The Context object for your activity or application.
|
|
* @param display The Display the hierarchy will be placed on.
|
|
* @param hostToken The host token, as discussed above.
|
|
* @param callsite The call site, used for tracking leakage of the host
|
|
* @hide
|
|
*/
|
|
public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
|
|
@Nullable InputTransferToken hostToken, @NonNull String callsite) {
|
|
mSurfaceControl = new SurfaceControl.Builder()
|
|
.setContainerLayer()
|
|
.setName("SurfaceControlViewHost")
|
|
.setCallsite("SurfaceControlViewHost[" + callsite + "]")
|
|
.build();
|
|
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
|
|
mSurfaceControl, hostToken);
|
|
|
|
mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout());
|
|
mCloseGuard.openWithCallSite("release", callsite);
|
|
setConfigCallback(context, display);
|
|
|
|
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
|
|
|
|
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
|
|
}
|
|
|
|
private void setConfigCallback(Context c, Display d) {
|
|
final IBinder token = c.getWindowContextToken();
|
|
mConfigChangedCallback = conf -> {
|
|
if (token instanceof WindowTokenClient) {
|
|
final WindowTokenClient w = (WindowTokenClient) token;
|
|
w.onConfigurationChanged(conf, d.getDisplayId(), true);
|
|
}
|
|
};
|
|
|
|
ViewRootImpl.addConfigCallback(mConfigChangedCallback);
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
if (mReleased) {
|
|
return;
|
|
}
|
|
if (mCloseGuard != null) {
|
|
mCloseGuard.warnIfOpen();
|
|
}
|
|
// We aren't on the UI thread here so we need to pass false to doDie
|
|
doRelease(false /* immediate */);
|
|
}
|
|
|
|
/**
|
|
* Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy.
|
|
* Rather than be directly reparented using {@link SurfaceControl.Transaction} this
|
|
* SurfacePackage should be passed to {@link SurfaceView#setChildSurfacePackage}
|
|
* which will not only reparent the Surface, but ensure the accessibility hierarchies
|
|
* are linked.
|
|
*/
|
|
public @Nullable SurfacePackage getSurfacePackage() {
|
|
if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
|
|
return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"),
|
|
mAccessibilityEmbeddedConnection, getInputTransferToken(), mRemoteInterface);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public @NonNull AttachedSurfaceControl getRootSurfaceControl() {
|
|
return mViewRoot;
|
|
}
|
|
|
|
/**
|
|
* Set the root view of the SurfaceControlViewHost. This view will render in to
|
|
* the SurfaceControl, and receive input based on the SurfaceControls positioning on
|
|
* screen. It will be laid as if it were in a window of the passed in width and height.
|
|
*
|
|
* @param view The View to add
|
|
* @param width The width to layout the View within, in pixels.
|
|
* @param height The height to layout the View within, in pixels.
|
|
*/
|
|
public void setView(@NonNull View view, int width, int height) {
|
|
final WindowManager.LayoutParams lp =
|
|
new WindowManager.LayoutParams(width, height,
|
|
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
|
|
setView(view, lp);
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setView(@NonNull View view, @NonNull WindowManager.LayoutParams attrs) {
|
|
Objects.requireNonNull(view);
|
|
attrs.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
|
|
addWindowToken(attrs);
|
|
view.setLayoutParams(attrs);
|
|
mViewRoot.setView(view, attrs, null);
|
|
mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent);
|
|
}
|
|
|
|
/**
|
|
* @return The view passed to setView, or null if none has been passed.
|
|
*/
|
|
public @Nullable View getView() {
|
|
return mViewRoot.getView();
|
|
}
|
|
|
|
/**
|
|
* @return the ViewRootImpl wrapped by this host.
|
|
* @hide
|
|
*/
|
|
public IWindow getWindowToken() {
|
|
return mViewRoot.mWindow;
|
|
}
|
|
|
|
/**
|
|
* @return the WindowlessWindowManager instance that this host is attached to.
|
|
* @hide
|
|
*/
|
|
public @NonNull WindowlessWindowManager getWindowlessWM() {
|
|
return mWm;
|
|
}
|
|
|
|
/**
|
|
* Forces relayout and draw and allows to set a custom callback when it is finished
|
|
* @hide
|
|
*/
|
|
public void relayout(WindowManager.LayoutParams attrs,
|
|
WindowlessWindowManager.ResizeCompleteCallback callback) {
|
|
mViewRoot.setLayoutParams(attrs, false);
|
|
mViewRoot.setReportNextDraw(true /* syncBuffer */, "scvh_relayout");
|
|
mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void relayout(WindowManager.LayoutParams attrs) {
|
|
mViewRoot.setLayoutParams(attrs, false);
|
|
}
|
|
|
|
/**
|
|
* Modify the size of the root view.
|
|
*
|
|
* @param width Width in pixels
|
|
* @param height Height in pixels
|
|
*/
|
|
public void relayout(int width, int height) {
|
|
final WindowManager.LayoutParams lp =
|
|
new WindowManager.LayoutParams(width, height,
|
|
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
|
|
relayout(lp);
|
|
}
|
|
|
|
/**
|
|
* Trigger the tear down of the embedded view hierarchy and release the SurfaceControl.
|
|
* This will result in onDispatchedFromWindow being dispatched to the embedded view hierarchy
|
|
* and render the object unusable.
|
|
*/
|
|
public void release() {
|
|
// ViewRoot will release mSurfaceControl for us.
|
|
doRelease(true /* immediate */);
|
|
}
|
|
|
|
private void doRelease(boolean immediate) {
|
|
if (mConfigChangedCallback != null) {
|
|
ViewRootImpl.removeConfigCallback(mConfigChangedCallback);
|
|
mConfigChangedCallback = null;
|
|
}
|
|
|
|
mViewRoot.die(immediate);
|
|
WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
|
|
mReleased = true;
|
|
mCloseGuard.close();
|
|
}
|
|
|
|
/**
|
|
* Returns an input token used which can be used to request focus on the embedded surface
|
|
* or to transfer touch gesture to the embedded surface.
|
|
*
|
|
* @hide
|
|
*/
|
|
public InputTransferToken getInputTransferToken() {
|
|
return mWm.getInputTransferToken(getWindowToken().asBinder());
|
|
}
|
|
|
|
private void addWindowToken(WindowManager.LayoutParams attrs) {
|
|
final WindowManager wm =
|
|
(WindowManager) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
|
|
attrs.token = wm.getDefaultToken();
|
|
}
|
|
|
|
/**
|
|
* Transfer the currently in progress touch gesture to the parent (if any) of this
|
|
* SurfaceControlViewHost. This requires that the SurfaceControlViewHost was created with an
|
|
* associated host {@link InputTransferToken}.
|
|
*
|
|
* @return Whether the touch stream was transferred.
|
|
* @deprecated Use {@link WindowManager#transferTouchGesture(InputTransferToken,
|
|
* InputTransferToken)} instead.
|
|
*/
|
|
@Deprecated
|
|
public boolean transferTouchGestureToHost() {
|
|
if (mViewRoot == null) {
|
|
return false;
|
|
}
|
|
final WindowManager wm = (WindowManager) mViewRoot.mContext.getSystemService(
|
|
Context.WINDOW_SERVICE);
|
|
InputTransferToken embeddedToken = getInputTransferToken();
|
|
InputTransferToken hostToken = mWm.mHostInputTransferToken;
|
|
if (embeddedToken == null || hostToken == null) {
|
|
Log.w(TAG, "Failed to transferTouchGestureToHost. Host or embedded token is null");
|
|
return false;
|
|
}
|
|
return wm.transferTouchGesture(getInputTransferToken(), mWm.mHostInputTransferToken);
|
|
}
|
|
}
|