• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.view;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.TestApi;
23 import android.content.Context;
24 import android.content.res.Configuration;
25 import android.graphics.PixelFormat;
26 import android.graphics.Rect;
27 import android.os.IBinder;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.RemoteException;
31 import android.util.Log;
32 import android.view.accessibility.IAccessibilityEmbeddedConnection;
33 import android.window.ISurfaceSyncGroup;
34 import android.window.InputTransferToken;
35 import android.window.WindowTokenClient;
36 
37 import com.android.window.flags.Flags;
38 
39 import dalvik.system.CloseGuard;
40 
41 import java.util.Objects;
42 import java.util.concurrent.CompletableFuture;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.TimeoutException;
46 
47 /**
48  * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
49  * will render in to a root SurfaceControl, and receive input based on the SurfaceControl's
50  * placement on-screen. The primary usage of this class is to embed a View hierarchy from
51  * one process in to another. After the SurfaceControlViewHost has been set up in the embedded
52  * content provider, we can send the {@link SurfaceControlViewHost.SurfacePackage}
53  * to the host process. The host process can then attach the hierarchy to a SurfaceView within
54  * its own by calling
55  * {@link SurfaceView#setChildSurfacePackage}.
56  */
57 public class SurfaceControlViewHost {
58     private final static String TAG = "SurfaceControlViewHost";
59     private final ViewRootImpl mViewRoot;
60     private final CloseGuard mCloseGuard = CloseGuard.get();
61     private final WindowlessWindowManager mWm;
62 
63     private SurfaceControl mSurfaceControl;
64     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
65     private boolean mReleased = false;
66 
67     private final class ISurfaceControlViewHostImpl extends ISurfaceControlViewHost.Stub {
68         @Override
onConfigurationChanged(Configuration configuration)69         public void onConfigurationChanged(Configuration configuration) {
70             if (mViewRoot == null) {
71                 return;
72             }
73             mViewRoot.mHandler.post(() -> {
74                 mWm.setConfiguration(configuration);
75                 if (mViewRoot != null) {
76                     mViewRoot.forceWmRelayout();
77                 }
78             });
79         }
80 
81         @Override
onDispatchDetachedFromWindow()82         public void onDispatchDetachedFromWindow() {
83             if (mViewRoot == null) {
84                 return;
85             }
86             mViewRoot.mHandler.post(() -> {
87                 release();
88             });
89         }
90 
91         @Override
onInsetsChanged(InsetsState state, Rect frame)92         public void onInsetsChanged(InsetsState state, Rect frame) {
93             if (mViewRoot != null) {
94                 mViewRoot.mHandler.post(() -> {
95                     mViewRoot.setOverrideInsetsFrame(frame);
96                 });
97             }
98             mWm.setInsetsState(state);
99         }
100 
101         @Override
getSurfaceSyncGroup()102         public ISurfaceSyncGroup getSurfaceSyncGroup() {
103             CompletableFuture<ISurfaceSyncGroup> surfaceSyncGroup = new CompletableFuture<>();
104             // If the call came from in process and it's already running on the UI thread, return
105             // results immediately instead of posting to the main thread. If we post to the main
106             // thread, it will block itself and the return value will always be null.
107             if (Thread.currentThread() == mViewRoot.mThread) {
108                 return mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup;
109             } else {
110                 mViewRoot.mHandler.post(
111                         () -> surfaceSyncGroup.complete(
112                                 mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup));
113             }
114             try {
115                 return surfaceSyncGroup.get(1, TimeUnit.SECONDS);
116             } catch (InterruptedException | ExecutionException | TimeoutException e) {
117                 Log.e(TAG, "Failed to get SurfaceSyncGroup for SCVH", e);
118             }
119             return null;
120         }
121 
122         @Override
attachParentInterface(@ullable ISurfaceControlViewHostParent parentInterface)123         public void attachParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
124             mViewRoot.mHandler.post(() -> mWm.setParentInterface(parentInterface));
125         }
126     }
127 
128     private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl();
129 
130     private ViewRootImpl.ConfigChangedCallback mConfigChangedCallback;
131 
132     /**
133      * Package encapsulating a Surface hierarchy which contains interactive view
134      * elements. It's expected to get this object from
135      * {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within
136      * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}.
137      *
138      * Note that each {@link SurfacePackage} must be released by calling
139      * {@link SurfacePackage#release}. However, if you use the recommended flow,
140      *  the framework will automatically handle the lifetime for you.
141      *
142      * 1. When sending the package to the remote process, return it from an AIDL method
143      * or manually use FLAG_WRITE_RETURN_VALUE in writeToParcel. This will automatically
144      * release the package in the local process.
145      * 2. In the remote process, consume the package using SurfaceView. This way the
146      * SurfaceView will take over the lifetime and call {@link SurfacePackage#release}
147      * for the user.
148      *
149      * One final note: The {@link SurfacePackage} lifetime is totally de-coupled
150      * from the lifetime of the underlying {@link SurfaceControlViewHost}. Regardless
151      * of the lifetime of the package the user should still call
152      * {@link SurfaceControlViewHost#release} when finished.
153      */
154     public static final class SurfacePackage implements Parcelable {
155         private SurfaceControl mSurfaceControl;
156         private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
157         private final InputTransferToken mInputTransferToken;
158         @NonNull
159         private final ISurfaceControlViewHost mRemoteInterface;
160 
SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection, InputTransferToken inputTransferToken, @NonNull ISurfaceControlViewHost ri)161         SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection,
162                 InputTransferToken inputTransferToken,
163                 @NonNull ISurfaceControlViewHost ri) {
164             mSurfaceControl = sc;
165             mAccessibilityEmbeddedConnection = connection;
166             mInputTransferToken = inputTransferToken;
167             mRemoteInterface = ri;
168         }
169 
170         /**
171          * Constructs a copy of {@code SurfacePackage} with an independent lifetime.
172          *
173          * The caller can use this to create an independent copy in situations where ownership of
174          * the {@code SurfacePackage} would be transferred elsewhere, such as attaching to a
175          * {@code SurfaceView}, returning as {@code Binder} result value, etc. The caller is
176          * responsible for releasing this copy when its done.
177          *
178          * @param other {@code SurfacePackage} to create a copy of.
179          */
SurfacePackage(@onNull SurfacePackage other)180         public SurfacePackage(@NonNull SurfacePackage other) {
181             SurfaceControl otherSurfaceControl = other.mSurfaceControl;
182             if (otherSurfaceControl != null && otherSurfaceControl.isValid()) {
183                 mSurfaceControl = new SurfaceControl(otherSurfaceControl, "SurfacePackage");
184             }
185             mAccessibilityEmbeddedConnection = other.mAccessibilityEmbeddedConnection;
186             mInputTransferToken = other.mInputTransferToken;
187             mRemoteInterface = other.mRemoteInterface;
188         }
189 
SurfacePackage(Parcel in)190         private SurfacePackage(Parcel in) {
191             mSurfaceControl = new SurfaceControl();
192             mSurfaceControl.readFromParcel(in);
193             mSurfaceControl.setUnreleasedWarningCallSite("SurfacePackage(Parcel)");
194             mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
195                     in.readStrongBinder());
196             mInputTransferToken = InputTransferToken.CREATOR.createFromParcel(in);
197             mRemoteInterface = ISurfaceControlViewHost.Stub.asInterface(in.readStrongBinder());
198         }
199 
200         /**
201          * Returns the {@link android.view.SurfaceControl} associated with this SurfacePackage for
202          * cases where more control is required.
203          *
204          * @return the SurfaceControl associated with this SurfacePackage and its containing
205          *     SurfaceControlViewHost
206          */
getSurfaceControl()207         public @NonNull SurfaceControl getSurfaceControl() {
208             return mSurfaceControl;
209         }
210 
211         /**
212          * Gets an accessibility embedded connection interface for this SurfaceControlViewHost.
213          *
214          * @return {@link IAccessibilityEmbeddedConnection} interface.
215          * @hide
216          */
getAccessibilityEmbeddedConnection()217         public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
218             return mAccessibilityEmbeddedConnection;
219         }
220 
221         /**
222          * @hide
223          */
224         @NonNull
getRemoteInterface()225         public ISurfaceControlViewHost getRemoteInterface() {
226             return mRemoteInterface;
227         }
228 
229         /**
230          * Forward a configuration to the remote SurfaceControlViewHost.
231          * This will cause View#onConfigurationChanged to be invoked on the remote
232          * end. This does not automatically cause the SurfaceControlViewHost
233          * to be resized. The root View of a SurfaceControlViewHost
234          * is more akin to a PopupWindow in that the size is user specified
235          * independent of configuration width and height.
236          *
237          * In order to receive the configuration change via
238          * {@link View#onConfigurationChanged}, the context used with the
239          * SurfaceControlViewHost and it's embedded view hierarchy must
240          * be a WindowContext obtained from {@link Context#createWindowContext}.
241          *
242          * If a regular service context is used, then your embedded view hierarchy
243          * will always perceive the global configuration.
244          *
245          * @param c The configuration to forward
246          */
notifyConfigurationChanged(@onNull Configuration c)247         public void notifyConfigurationChanged(@NonNull Configuration c) {
248             try {
249                 getRemoteInterface().onConfigurationChanged(c);
250             } catch (RemoteException e) {
251                 e.rethrowAsRuntimeException();
252             }
253         }
254 
255         /**
256          * Tear down the remote SurfaceControlViewHost and cause
257          * View#onDetachedFromWindow to be invoked on the other side.
258          */
notifyDetachedFromWindow()259         public void notifyDetachedFromWindow() {
260             try {
261                 getRemoteInterface().onDispatchDetachedFromWindow();
262             } catch (RemoteException e) {
263                 e.rethrowAsRuntimeException();
264             }
265         }
266 
267         @Override
describeContents()268         public int describeContents() {
269             return 0;
270         }
271 
272         @Override
writeToParcel(@onNull Parcel out, int flags)273         public void writeToParcel(@NonNull Parcel out, int flags) {
274             mSurfaceControl.writeToParcel(out, flags);
275             out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
276             mInputTransferToken.writeToParcel(out, flags);
277             out.writeStrongBinder(mRemoteInterface.asBinder());
278         }
279 
280         /**
281          * Release the {@link SurfaceControl} associated with this package.
282          * It's not necessary to call this if you pass the package to
283          * {@link SurfaceView#setChildSurfacePackage} as {@link SurfaceView} will
284          * take ownership in that case.
285          */
release()286         public void release() {
287             if (mSurfaceControl != null) {
288                 mSurfaceControl.release();
289              }
290              mSurfaceControl = null;
291         }
292 
293         /**
294          * Gets an {@link InputTransferToken} which can be used to request focus on the embedded
295          * surface or to transfer touch gesture to the embedded surface.
296          *
297          * @return the InputTransferToken associated with {@link SurfacePackage} or {@code null} if
298          * the embedded hasn't set up its view or doesn't have input.
299          * @see WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
300          */
301         @Nullable
302         @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
getInputTransferToken()303         public InputTransferToken getInputTransferToken() {
304             return mInputTransferToken;
305         }
306 
307         @Override
toString()308         public String toString() {
309             return "{inputTransferToken=" + getInputTransferToken() + " remoteInterface="
310                     + getRemoteInterface() + "}";
311         }
312 
313         public static final @NonNull Creator<SurfacePackage> CREATOR
314              = new Creator<SurfacePackage>() {
315                      public SurfacePackage createFromParcel(Parcel in) {
316                          return new SurfacePackage(in);
317                      }
318                      public SurfacePackage[] newArray(int size) {
319                          return new SurfacePackage[size];
320                      }
321              };
322     }
323 
324     /** @hide */
SurfaceControlViewHost(@onNull Context c, @NonNull Display d, @NonNull WindowlessWindowManager wwm, @NonNull String callsite)325     public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
326             @NonNull WindowlessWindowManager wwm, @NonNull String callsite) {
327         mSurfaceControl = wwm.mRootSurface;
328         mWm = wwm;
329         mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout());
330         mCloseGuard.openWithCallSite("release", callsite);
331         setConfigCallback(c, d);
332 
333         WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
334 
335         mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
336     }
337 
338     /**
339      * Construct a new SurfaceControlViewHost. The root Surface will be
340      * allocated internally and is accessible via getSurfacePackage().
341      *
342      * The {@param hostToken} parameter, primarily used for ANR reporting,
343      * must be obtained from whomever will be hosting the embedded hierarchy.
344      * It's accessible from {@link SurfaceView#getHostToken}.
345      *
346      * @param context The Context object for your activity or application.
347      * @param display The Display the hierarchy will be placed on.
348      * @param hostToken The host token, as discussed above.
349      */
SurfaceControlViewHost(@onNull Context context, @NonNull Display display, @Nullable IBinder hostToken)350     public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
351             @Nullable IBinder hostToken) {
352         this(context, display, hostToken == null ? null : new InputTransferToken(hostToken),
353                 "untracked");
354 
355     }
356 
357     /**
358      * Construct a new SurfaceControlViewHost. The root Surface will be
359      * allocated internally and is accessible via getSurfacePackage().
360      * <p>
361      * The hostInputTransferToken parameter allows the host and embedded to be associated with
362      * each other to allow transferring touch gesture and focus. This is also used for ANR
363      * reporting. It's accessible from {@link AttachedSurfaceControl#getInputTransferToken()}.
364      *
365      * @param context                The Context object for your activity or application.
366      * @param display                The Display the hierarchy will be placed on.
367      * @param hostInputTransferToken The host input transfer token, as discussed above.
368      */
369     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
SurfaceControlViewHost(@onNull Context context, @NonNull Display display, @Nullable InputTransferToken hostInputTransferToken)370     public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
371             @Nullable InputTransferToken hostInputTransferToken) {
372         this(context, display, hostInputTransferToken, "untracked");
373     }
374 
375     /**
376      * Construct a new SurfaceControlViewHost. The root Surface will be
377      * allocated internally and is accessible via getSurfacePackage().
378      *
379      * The {@param hostToken} parameter, primarily used for ANR reporting,
380      * must be obtained from whomever will be hosting the embedded hierarchy.
381      * It's accessible from {@link SurfaceView#getHostToken}.
382      *
383      * @param context The Context object for your activity or application.
384      * @param display The Display the hierarchy will be placed on.
385      * @param hostToken The host token, as discussed above.
386      * @param callsite The call site, used for tracking leakage of the host
387      * @hide
388      */
SurfaceControlViewHost(@onNull Context context, @NonNull Display display, @Nullable InputTransferToken hostToken, @NonNull String callsite)389     public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
390             @Nullable InputTransferToken hostToken, @NonNull String callsite) {
391         mSurfaceControl = new SurfaceControl.Builder()
392                 .setContainerLayer()
393                 .setName("SurfaceControlViewHost")
394                 .setCallsite("SurfaceControlViewHost[" + callsite + "]")
395                 .build();
396         mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
397                 mSurfaceControl, hostToken);
398 
399         mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout());
400         mCloseGuard.openWithCallSite("release", callsite);
401         setConfigCallback(context, display);
402 
403         WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
404 
405         mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
406     }
407 
setConfigCallback(Context c, Display d)408     private void setConfigCallback(Context c, Display d) {
409         final IBinder token = c.getWindowContextToken();
410         mConfigChangedCallback = conf -> {
411             if (token instanceof WindowTokenClient) {
412                 final WindowTokenClient w = (WindowTokenClient)  token;
413                 w.onConfigurationChanged(conf, d.getDisplayId(), true);
414             }
415         };
416 
417         ViewRootImpl.addConfigCallback(mConfigChangedCallback);
418     }
419 
420     /**
421      * @hide
422      */
423     @Override
finalize()424     protected void finalize() throws Throwable {
425         if (mReleased) {
426             return;
427         }
428         if (mCloseGuard != null) {
429             mCloseGuard.warnIfOpen();
430         }
431         // We aren't on the UI thread here so we need to pass false to doDie
432         doRelease(false /* immediate */);
433     }
434 
435     /**
436      * Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy.
437      * Rather than be directly reparented using {@link SurfaceControl.Transaction} this
438      * SurfacePackage should be passed to {@link SurfaceView#setChildSurfacePackage}
439      * which will not only reparent the Surface, but ensure the accessibility hierarchies
440      * are linked.
441      */
getSurfacePackage()442     public @Nullable SurfacePackage getSurfacePackage() {
443         if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
444             return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"),
445                 mAccessibilityEmbeddedConnection, getInputTransferToken(), mRemoteInterface);
446         } else {
447             return null;
448         }
449     }
450 
451     /**
452      * @hide
453      */
getRootSurfaceControl()454     public @NonNull AttachedSurfaceControl getRootSurfaceControl() {
455         return mViewRoot;
456     }
457 
458     /**
459      * Set the root view of the SurfaceControlViewHost. This view will render in to
460      * the SurfaceControl, and receive input based on the SurfaceControls positioning on
461      * screen. It will be laid as if it were in a window of the passed in width and height.
462      *
463      * @param view The View to add
464      * @param width The width to layout the View within, in pixels.
465      * @param height The height to layout the View within, in pixels.
466      */
setView(@onNull View view, int width, int height)467     public void setView(@NonNull View view, int width, int height) {
468         final WindowManager.LayoutParams lp =
469                 new WindowManager.LayoutParams(width, height,
470                         WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
471         setView(view, lp);
472     }
473 
474     /**
475      * @hide
476      */
477     @TestApi
setView(@onNull View view, @NonNull WindowManager.LayoutParams attrs)478     public void setView(@NonNull View view, @NonNull WindowManager.LayoutParams attrs) {
479         Objects.requireNonNull(view);
480         attrs.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
481         addWindowToken(attrs);
482         view.setLayoutParams(attrs);
483         mViewRoot.setView(view, attrs, null);
484         mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent);
485     }
486 
487     /**
488      * @return The view passed to setView, or null if none has been passed.
489      */
getView()490     public @Nullable View getView() {
491         return mViewRoot.getView();
492     }
493 
494     /**
495      * @return the ViewRootImpl wrapped by this host.
496      * @hide
497      */
getWindowToken()498     public IWindow getWindowToken() {
499         return mViewRoot.mWindow;
500     }
501 
502     /**
503      * @return the WindowlessWindowManager instance that this host is attached to.
504      * @hide
505      */
getWindowlessWM()506     public @NonNull WindowlessWindowManager getWindowlessWM() {
507         return mWm;
508     }
509 
510     /**
511      * Forces relayout and draw and allows to set a custom callback when it is finished
512      * @hide
513      */
relayout(WindowManager.LayoutParams attrs, WindowlessWindowManager.ResizeCompleteCallback callback)514     public void relayout(WindowManager.LayoutParams attrs,
515             WindowlessWindowManager.ResizeCompleteCallback callback) {
516         mViewRoot.setLayoutParams(attrs, false);
517         mViewRoot.setReportNextDraw(true /* syncBuffer */, "scvh_relayout");
518         mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
519     }
520 
521     /**
522      * @hide
523      */
524     @TestApi
relayout(WindowManager.LayoutParams attrs)525     public void relayout(WindowManager.LayoutParams attrs) {
526         mViewRoot.setLayoutParams(attrs, false);
527     }
528 
529     /**
530      * Modify the size of the root view.
531      *
532      * @param width Width in pixels
533      * @param height Height in pixels
534      */
relayout(int width, int height)535     public void relayout(int width, int height) {
536         final WindowManager.LayoutParams lp =
537                 new WindowManager.LayoutParams(width, height,
538                         WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
539         relayout(lp);
540     }
541 
542     /**
543      * Trigger the tear down of the embedded view hierarchy and release the SurfaceControl.
544      * This will result in onDispatchedFromWindow being dispatched to the embedded view hierarchy
545      * and render the object unusable.
546      */
release()547     public void release() {
548         // ViewRoot will release mSurfaceControl for us.
549         doRelease(true /* immediate */);
550     }
551 
doRelease(boolean immediate)552     private void doRelease(boolean immediate) {
553         if (mConfigChangedCallback != null) {
554             ViewRootImpl.removeConfigCallback(mConfigChangedCallback);
555             mConfigChangedCallback = null;
556         }
557 
558         mViewRoot.die(immediate);
559         WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
560         mReleased = true;
561         mCloseGuard.close();
562     }
563 
564     /**
565      * Returns an input token used which can be used to request focus on the embedded surface
566      * or to transfer touch gesture to the embedded surface.
567      *
568      * @hide
569      */
getInputTransferToken()570     public InputTransferToken getInputTransferToken() {
571         return mWm.getInputTransferToken(getWindowToken().asBinder());
572     }
573 
addWindowToken(WindowManager.LayoutParams attrs)574     private void addWindowToken(WindowManager.LayoutParams attrs) {
575         final WindowManager wm =
576                 (WindowManager) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
577         attrs.token = wm.getDefaultToken();
578     }
579 
580     /**
581      * Transfer the currently in progress touch gesture to the parent (if any) of this
582      * SurfaceControlViewHost. This requires that the SurfaceControlViewHost was created with an
583      * associated host {@link InputTransferToken}.
584      *
585      * @return Whether the touch stream was transferred.
586      * @deprecated Use {@link WindowManager#transferTouchGesture(InputTransferToken,
587      * InputTransferToken)} instead.
588      */
589     @Deprecated
transferTouchGestureToHost()590     public boolean transferTouchGestureToHost() {
591         if (mViewRoot == null) {
592             return false;
593         }
594         final WindowManager wm = (WindowManager) mViewRoot.mContext.getSystemService(
595                 Context.WINDOW_SERVICE);
596         InputTransferToken embeddedToken = getInputTransferToken();
597         InputTransferToken hostToken = mWm.mHostInputTransferToken;
598         if (embeddedToken == null || hostToken == null) {
599             Log.w(TAG, "Failed to transferTouchGestureToHost. Host or embedded token is null");
600             return false;
601         }
602         return wm.transferTouchGesture(getInputTransferToken(), mWm.mHostInputTransferToken);
603     }
604 }
605