Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceInflater.java

Issue 1361153004: [Contextual Search] Adds offscreen View rendering capability (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sync & rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/widget/ReaderModeControl.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.ui.resources.dynamics;
6
7 import android.content.Context;
8 import android.view.LayoutInflater;
9 import android.view.View;
10 import android.view.ViewGroup;
11 import android.view.ViewTreeObserver;
12
13 /**
14 * ViewResourceInflater is a utility class that facilitates using an Android Vie w as a dynamic
15 * resource, which can be later used as a compositor layer. This class assumes t hat the View
16 * is defined declaratively, using a XML Layout file, and that the View that is going to be
17 * inflated is the single top-level View of the layout (its root).
18 *
19 * By default, the View is inflated without being attached to the hierarchy, whi ch allows
20 * subclasses to read/modify the View "offscreen", via the method {@link #onFini shInflate()}.
21 * Only when a new snapshot of the View is required, which happens when the meth od
22 * {@link #invalidate()} is called, and the View is automatically detached from the
23 * hierarchy after the snapshot is captured.
24 *
25 * There's also an option to not attach to the hierarchy at all, by overriding t he method
26 * {@link #shouldAttachView()} and making it return false (the default is yes). In this case
27 * the changes to the View will always be "offscreen". By default, an unspecifie d value of
28 * {@link View.MeasureSpec} will de used to determine the width and height of th e View.
29 * It's possible to specify custom size constraints by overriding the methods
30 * {@link #getWidthMeasureSpec()} and {@link #getHeightMeasureSpec()}.
31 */
32 public class ViewResourceInflater {
33
34 /**
35 * The id of the XML Layout that describes the View.
36 */
37 private int mLayoutId;
38
39 /**
40 * The id of the View being inflated, which must be the root of the given La yout.
41 */
42 private int mViewId;
43
44 /**
45 * The Context used to inflate the View.
46 */
47 private Context mContext;
48
49 /**
50 * The ViewGroup container used to inflate the View.
51 */
52 private ViewGroup mContainer;
53
54 /**
55 * The DynamicResourceLoader used to manage resources generated dynamically.
56 */
57 private DynamicResourceLoader mResourceLoader;
58
59 /**
60 * The ViewResourceAdapter used to capture snapshots of the View.
61 */
62 private ViewResourceAdapter mResourceAdapter;
63
64 /**
65 * The inflated View.
66 */
67 private View mView;
68
69 /**
70 * Whether the View is invalided.
71 */
72 private boolean mIsInvalidated;
73
74 /**
75 * Whether the View is attached to the hierarchy.
76 */
77 private boolean mIsAttached;
78
79 /**
80 * The ViewInflaterOnDrawListener used to track changes in the View when att ached.
81 */
82 private ViewInflaterOnDrawListener mOnDrawListener;
83
84 /**
85 * The invalid ID.
86 */
87 private static final int INVALID_ID = -1;
88
89 /**
90 * @param layoutId The XML Layout that declares the View.
91 * @param viewId The id of the root View of the Layout.
92 * @param context The Android Context used to inflate the View.
93 * @param container The container View used to inflate the View.
94 * @param resourceLoader The resource loader that will handle the snapsho t capturing.
95 */
96 public ViewResourceInflater(int layoutId,
97 int viewId,
98 Context context,
99 ViewGroup container,
100 DynamicResourceLoader resourceLoader) {
101 mLayoutId = layoutId;
102 mViewId = viewId;
103 mContext = context;
104 mContainer = container;
105 mResourceLoader = resourceLoader;
106 }
107
108 /**
109 * Inflate the layout.
110 */
111 public void inflate() {
112 if (mView != null) return;
113
114 // Inflate the View without attaching to hierarchy (attachToRoot param i s false).
115 mView = LayoutInflater.from(mContext).inflate(mLayoutId, mContainer, fal se);
116
117 // Make sure the View we just inflated is the right one.
118 assert mView.getId() == mViewId;
119
120 // Allow subclasses to access/modify the View before it's attached
121 // to the hierarchy (if allowed) or snapshots are captured.
122 onFinishInflate();
123
124 registerResource();
125 }
126
127 /**
128 * Invalidate the inflated View, causing a snapshot of the View to be captur ed.
129 */
130 public void invalidate() {
131 // View must be inflated at this point. If it's not, do it now.
132 if (mView == null) {
133 inflate();
134 }
135
136 mIsInvalidated = true;
137
138 // If the View is already attached, we don't need to do anything because the
139 // snapshot will be captured automatically when the View is drawn.
140 if (!mIsAttached) {
141 if (shouldAttachView()) {
142 // TODO(pedrosimonetti): investigate if complex views can be ren dered offline.
143 // NOTE(pedrosimonetti): it seems that complex views don't get r endered
144 // properly if not attached to the hierarchy. The problem seem t o be related
145 // to the use of the property "layout_gravity: end", possibly in combination
146 // of other things like elastic views (layout_weight: 1) and/or fading edges.
147 attachView();
148 } else {
149 // When the View is not attached, we need to manually layout the View
150 // and invalidate the resource in order to capture a new snapsho t.
151 layout();
152 invalidateResource();
153 }
154 }
155 }
156
157 /**
158 * Destroy the instance.
159 */
160 public void destroy() {
161 if (mView == null) return;
162
163 unregisterResource();
164
165 detachView();
166 mView = null;
167
168 mLayoutId = INVALID_ID;
169 mViewId = INVALID_ID;
170
171 mContext = null;
172 mContainer = null;
173 mResourceLoader = null;
174 }
175
176 /**
177 * @return The measured width of the inflated View.
178 */
179 public int getMeasuredWidth() {
180 // View must be inflated at this point.
181 assert mView != null;
182
183 return mView.getMeasuredWidth();
184 }
185
186 /**
187 * @return The measured height of the inflated View.
188 */
189 public int getMeasuredHeight() {
190 // View must be inflated at this point.
191 assert mView != null;
192
193 return mView.getMeasuredHeight();
194 }
195
196 /**
197 * @return The id of View, which is used as an identifier for the resource l oader.
198 */
199 public int getViewId() {
200 return mViewId;
201 }
202
203 /**
204 * The callback called after inflating the View, allowing subclasses to acce ss/modify
205 * the View before it's attached to the hierarchy (if allowed) or snapshots are captured.
206 */
207 protected void onFinishInflate() {}
208
209 /**
210 * NOTE(pedrosimonetti): Complex views don't fully work when not attached to the hierarchy.
211 * @return Whether the View should be attached to the hierarchy after being inflated.
212 * Subclasses should override this method to change the default beha vior.
213 */
214 protected boolean shouldAttachView() {
215 return true;
216 }
217
218 /**
219 * @return Whether the View should be detached from the hierarchy after bein g captured.
220 * Subclasses should override this method to change the default beha vior.
221 */
222 protected boolean shouldDetachViewAfterCapturing() {
223 return true;
224 }
225
226 /**
227 * @return The MeasureSpec used for calculating the width of the offscreen V iew.
228 * Subclasses should override this method to specify measurements.
229 * By default, this method returns an unspecified MeasureSpec.
230 */
231 protected int getWidthMeasureSpec() {
232 return getUnspecifiedMeasureSpec();
233 }
234
235 /**
236 * @return The MeasureSpec used for calculating the height of the offscreen View.
237 * Subclasses should override this method to specify measurements.
238 * By default, this method returns an unspecified MeasureSpec.
239 */
240 protected int getHeightMeasureSpec() {
241 return getUnspecifiedMeasureSpec();
242 }
243
244 /**
245 * @return The View resource.
246 */
247 protected View getView() {
248 return mView;
249 }
250
251 /**
252 * Attach the View to the hierarchy.
253 */
254 private void attachView() {
255 if (!mIsAttached) {
256 assert mView.getParent() == null;
257 mContainer.addView(mView);
258 mIsAttached = true;
259
260 if (mOnDrawListener == null) {
261 // Add a draw listener. For now on, changes in the View will cau se a
262 // new snapshot to be captured, if the ViewResourceInflater was invalidated.
263 mOnDrawListener = new ViewInflaterOnDrawListener();
264 mView.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
265 }
266 }
267 }
268
269 /**
270 * Detach the View from the hierarchy.
271 */
272 private void detachView() {
273 if (mIsAttached) {
274 if (mOnDrawListener != null) {
275 mView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener );
276 mOnDrawListener = null;
277 }
278
279 assert mView.getParent() != null;
280 mContainer.removeView(mView);
281 mIsAttached = false;
282 }
283 }
284
285 /**
286 * Layout the View. This is to be used when the View is not attached to the hierarchy.
287 */
288 private void layout() {
289 // View must be inflated at this point.
290 assert mView != null;
291
292 mView.measure(getWidthMeasureSpec(), getHeightMeasureSpec());
293 mView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
294 }
295
296 /**
297 * @return An unspecified MeasureSpec value.
298 */
299 private int getUnspecifiedMeasureSpec() {
300 return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) ;
301 }
302
303 /**
304 * Register the resource and creates an adapter for it.
305 */
306 private void registerResource() {
307 if (mResourceAdapter == null) {
308 mResourceAdapter = new ViewInflaterAdapter(mView.findViewById(mViewI d));
309 }
310
311 if (mResourceLoader != null) {
312 mResourceLoader.registerResource(mViewId, mResourceAdapter);
313 }
314 }
315
316 /**
317 * Unregister the resource and destroys the adapter.
318 */
319 private void unregisterResource() {
320 if (mResourceLoader != null) {
321 mResourceLoader.unregisterResource(mViewId);
322 }
323
324 mResourceAdapter = null;
325 }
326
327 /**
328 * Invalidate the resource, which will cause a new snapshot to be captured.
329 */
330 private void invalidateResource() {
331 if (mIsInvalidated && mView != null && mResourceAdapter != null) {
332 mIsInvalidated = false;
333 mResourceAdapter.invalidate(null);
334 }
335 }
336
337 /**
338 * A custom {@link ViewResourceAdapter} that calls the method {@link #onCapt ureEnd()}.
339 */
340 private class ViewInflaterAdapter extends ViewResourceAdapter {
341 public ViewInflaterAdapter(View view) {
342 super(view);
343 }
344
345 @Override
346 protected void onCaptureEnd() {
347 ViewResourceInflater.this.onCaptureEnd();
348 }
349 }
350
351 /**
352 * Called when a snapshot is captured.
353 */
354 private void onCaptureEnd() {
355 if (shouldDetachViewAfterCapturing()) {
356 detachView();
357 }
358 }
359
360 /**
361 * A custom {@link ViewTreeObserver.OnDrawListener} that calls the method {@ link #onDraw()}.
362 */
363 private class ViewInflaterOnDrawListener implements ViewTreeObserver.OnDrawL istener {
364 @Override
365 public void onDraw() {
366 ViewResourceInflater.this.onDraw();
367 }
368 }
369
370 /**
371 * Called when the View is drawn,
372 */
373 private void onDraw() {
374 invalidateResource();
375 }
376 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/widget/ReaderModeControl.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698