blob: 7ec008c901bc10f52643aefe0b280dd405577b13 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
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
17package android.view;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.TestApi;
22import android.content.Context;
23import android.graphics.PixelFormat;
24import android.os.IBinder;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.view.accessibility.IAccessibilityEmbeddedConnection;
28
29import java.util.Objects;
30
31/**
32 * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
33 * will render in to a root SurfaceControl, and receive input based on the SurfaceControl's
34 * placement on-screen. The primary usage of this class is to embed a View hierarchy from
35 * one process in to another. After the SurfaceControlViewHost has been set up in the embedded
36 * content provider, we can send the {@link SurfaceControlViewHost.SurfacePackage}
37 * to the host process. The host process can then attach the hierarchy to a SurfaceView within
38 * its own by calling
39 * {@link SurfaceView#setChildSurfacePackage}.
40 */
41public class SurfaceControlViewHost {
42 private final ViewRootImpl mViewRoot;
43 private WindowlessWindowManager mWm;
44
45 private SurfaceControl mSurfaceControl;
46 private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
47
48 /**
49 * Package encapsulating a Surface hierarchy which contains interactive view
50 * elements. It's expected to get this object from
51 * {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within
52 * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}.
53 *
54 * Note that each {@link SurfacePackage} must be released by calling
55 * {@link SurfacePackage#release}. However, if you use the recommended flow,
56 * the framework will automatically handle the lifetime for you.
57 *
58 * 1. When sending the package to the remote process, return it from an AIDL method
59 * or manually use FLAG_WRITE_RETURN_VALUE in writeToParcel. This will automatically
60 * release the package in the local process.
61 * 2. In the remote process, consume the package using SurfaceView. This way the
62 * SurfaceView will take over the lifetime and call {@link SurfacePackage#release}
63 * for the user.
64 *
65 * One final note: The {@link SurfacePackage} lifetime is totally de-coupled
66 * from the lifetime of the underlying {@link SurfaceControlViewHost}. Regardless
67 * of the lifetime of the package the user should still call
68 * {@link SurfaceControlViewHost#release} when finished.
69 */
70 public static final class SurfacePackage implements Parcelable {
71 private SurfaceControl mSurfaceControl;
72 private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
73
74 SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection) {
75 mSurfaceControl = sc;
76 mAccessibilityEmbeddedConnection = connection;
77 }
78
79 private SurfacePackage(Parcel in) {
80 mSurfaceControl = new SurfaceControl();
81 mSurfaceControl.readFromParcel(in);
82 mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
83 in.readStrongBinder());
84 }
85
86 /**
87 * Use {@link SurfaceView#setChildSurfacePackage} or manually fix
88 * accessibility (see SurfaceView implementation).
89 * @hide
90 */
91 public @NonNull SurfaceControl getSurfaceControl() {
92 return mSurfaceControl;
93 }
94
95 /**
96 * Gets an accessibility embedded connection interface for this SurfaceControlViewHost.
97 *
98 * @return {@link IAccessibilityEmbeddedConnection} interface.
99 * @hide
100 */
101 public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
102 return mAccessibilityEmbeddedConnection;
103 }
104
105 @Override
106 public int describeContents() {
107 return 0;
108 }
109
110 @Override
111 public void writeToParcel(@NonNull Parcel out, int flags) {
112 mSurfaceControl.writeToParcel(out, flags);
113 out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
114 }
115
116 /**
117 * Release the {@link SurfaceControl} associated with this package.
118 * It's not necessary to call this if you pass the package to
119 * {@link SurfaceView#setChildSurfacePackage} as {@link SurfaceView} will
120 * take ownership in that case.
121 */
122 public void release() {
123 if (mSurfaceControl != null) {
124 mSurfaceControl.release();
125 }
126 mSurfaceControl = null;
127 }
128
129 public static final @NonNull Creator<SurfacePackage> CREATOR
130 = new Creator<SurfacePackage>() {
131 public SurfacePackage createFromParcel(Parcel in) {
132 return new SurfacePackage(in);
133 }
134 public SurfacePackage[] newArray(int size) {
135 return new SurfacePackage[size];
136 }
137 };
138 }
139
140 /** @hide */
141 public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
142 @NonNull WindowlessWindowManager wwm) {
143 this(c, d, wwm, false /* useSfChoreographer */);
144 }
145
146 /** @hide */
147 public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
148 @NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
149 mWm = wwm;
150 mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer);
151 mViewRoot.forceDisableBLAST();
152 mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
153 }
154
155 /**
156 * Construct a new SurfaceControlViewHost. The root Surface will be
157 * allocated internally and is accessible via getSurfacePackage().
158 *
159 * The {@param hostToken} parameter, primarily used for ANR reporting,
160 * must be obtained from whomever will be hosting the embedded hierarchy.
161 * It's accessible from {@link SurfaceView#getHostToken}.
162 *
163 * @param context The Context object for your activity or application.
164 * @param display The Display the hierarchy will be placed on.
165 * @param hostToken The host token, as discussed above.
166 */
167 public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
168 @Nullable IBinder hostToken) {
169 mSurfaceControl = new SurfaceControl.Builder()
170 .setContainerLayer()
171 .setName("SurfaceControlViewHost")
172 .build();
173 mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
174 mSurfaceControl, hostToken);
175 mViewRoot = new ViewRootImpl(context, display, mWm);
176 mViewRoot.forceDisableBLAST();
177 mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
178 }
179
180 /**
181 * Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy.
182 * Rather than be directly reparented using {@link SurfaceControl.Transaction} this
183 * SurfacePackage should be passed to {@link SurfaceView#setChildSurfacePackage}
184 * which will not only reparent the Surface, but ensure the accessibility hierarchies
185 * are linked.
186 */
187 public @Nullable SurfacePackage getSurfacePackage() {
188 if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
189 return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection);
190 } else {
191 return null;
192 }
193 }
194
195 /**
196 * @hide
197 */
198 @TestApi
199 public void setView(@NonNull View view, @NonNull WindowManager.LayoutParams attrs) {
200 Objects.requireNonNull(view);
201 mViewRoot.setView(view, attrs, null);
202 }
203
204 /**
205 * Set the root view of the SurfaceControlViewHost. This view will render in to
206 * the SurfaceControl, and receive input based on the SurfaceControls positioning on
207 * screen. It will be laid as if it were in a window of the passed in width and height.
208 *
209 * @param view The View to add
210 * @param width The width to layout the View within, in pixels.
211 * @param height The height to layout the View within, in pixels.
212 */
213 public void setView(@NonNull View view, int width, int height) {
214 final WindowManager.LayoutParams lp =
215 new WindowManager.LayoutParams(width, height,
216 WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
217 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
218 setView(view, lp);
219 }
220
221 /**
222 * @return The view passed to setView, or null if none has been passed.
223 */
224 public @Nullable View getView() {
225 return mViewRoot.getView();
226 }
227
228 /**
229 * @return the ViewRootImpl wrapped by this host.
230 * @hide
231 */
232 public IWindow getWindowToken() {
233 return mViewRoot.mWindow;
234 }
235
236 /**
237 * @return the WindowlessWindowManager instance that this host is attached to.
238 * @hide
239 */
240 public @NonNull WindowlessWindowManager getWindowlessWM() {
241 return mWm;
242 }
243
244 /**
245 * @hide
246 */
247 @TestApi
248 public void relayout(WindowManager.LayoutParams attrs) {
249 mViewRoot.setLayoutParams(attrs, false);
250 mViewRoot.setReportNextDraw();
251 mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), (SurfaceControl.Transaction t) -> {
252 t.apply();
253 });
254 }
255
256 /**
257 * Modify the size of the root view.
258 *
259 * @param width Width in pixels
260 * @param height Height in pixels
261 */
262 public void relayout(int width, int height) {
263 final WindowManager.LayoutParams lp =
264 new WindowManager.LayoutParams(width, height,
265 WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
266 relayout(lp);
267 }
268
269 /**
270 * Trigger the tear down of the embedded view hierarchy and release the SurfaceControl.
271 * This will result in onDispatchedFromWindow being dispatched to the embedded view hierarchy
272 * and render the object unusable.
273 */
274 public void release() {
275 mViewRoot.die(false /* immediate */);
276 mSurfaceControl.release();
277 }
278
279 /**
280 * Tell this viewroot to clean itself up.
281 * @hide
282 */
283 public void die() {
284 mViewRoot.die(false /* immediate */);
285 }
286}