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

Side by Side Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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
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.chrome.browser.compositor.layouts;
6
7 import android.graphics.Point;
8 import android.graphics.Rect;
9 import android.graphics.RectF;
10 import android.os.SystemClock;
11 import android.view.MotionEvent;
12 import android.view.View;
13 import android.view.ViewGroup;
14
15 import org.chromium.base.ObserverList;
16 import org.chromium.base.TraceEvent;
17 import org.chromium.base.VisibleForTesting;
18 import org.chromium.base.annotations.SuppressFBWarnings;
19 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
20 import org.chromium.chrome.browser.compositor.layouts.Layout.SizingFlags;
21 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
22 import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
23 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
24 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandl er;
25 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
26 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilterHos t;
27 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDe legate;
28 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
29 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
30 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
31 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
32 import org.chromium.content.browser.SPenSupport;
33 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
34
35 import java.util.List;
36
37 /**
38 * A class that is responsible for managing an active {@link Layout} to show to the screen. This
39 * includes lifecycle managment like showing/hiding this {@link Layout}.
40 */
41 public abstract class LayoutManager implements LayoutUpdateHost, LayoutProvider, EventFilterHost {
42 /** Sampling at 60 fps. */
43 private static final long FRAME_DELTA_TIME_MS = 16;
44
45 /** Used to convert pixels to dp. */
46 protected final float mPxToDp;
47
48 /** The {@link LayoutManagerHost}, who is responsible for showing the active {@link Layout}. */
49 protected final LayoutManagerHost mHost;
50
51 /** The last X coordinate of the last {@link MotionEvent#ACTION_DOWN} event. */
52 protected int mLastTapX;
53
54 /** The last Y coordinate of the last {@link MotionEvent#ACTION_DOWN} event. */
55 protected int mLastTapY;
56
57 // External Dependencies
58 private TabModelSelector mTabModelSelector;
59 private ViewGroup mContentContainer;
60
61 // External Observers
62 private final ObserverList<SceneChangeObserver> mSceneChangeObservers;
63
64 // Current Layout State
65 private Layout mActiveLayout;
66 private Layout mNextActiveLayout;
67
68 // Current Event Fitler State
69 private EventFilter mActiveEventFilter;
70
71 // Internal State
72 private int mFullscreenToken = FullscreenManager.INVALID_TOKEN;
73 private boolean mUpdateRequested;
74
75 // Sizing State
76 private final Rect mLastViewportPx = new Rect();
77 private final Rect mLastVisibleViewportPx = new Rect();
78 private final Rect mLastFullscreenViewportPx = new Rect();
79 protected final RectF mLastViewportDp = new RectF();
80 protected final RectF mLastVisibleViewportDp = new RectF();
81 protected final RectF mLastFullscreenViewportDp = new RectF();
82
83 protected float mLastContentWidthDp;
84 protected float mLastContentHeightDp;
85 protected float mLastHeightMinusTopControlsDp;
86
87 private final RectF mCachedRectF = new RectF();
88 private final Rect mCachedRect = new Rect();
89 private final Point mCachedPoint = new Point();
90
91 /**
92 * Creates a {@link LayoutManager} instance.
93 * @param host A {@link LayoutManagerHost} instance.
94 */
95 public LayoutManager(LayoutManagerHost host) {
96 mHost = host;
97 mPxToDp = 1.f / mHost.getContext().getResources().getDisplayMetrics().de nsity;
98 mSceneChangeObservers = new ObserverList<SceneChangeObserver>();
99
100 int hostWidth = host.getWidth();
101 int hostHeight = host.getHeight();
102 mLastViewportPx.set(0, 0, hostWidth, hostHeight);
103 mLastVisibleViewportPx.set(0, 0, hostWidth, hostHeight);
104 mLastFullscreenViewportPx.set(0, 0, hostWidth, hostHeight);
105
106 mLastContentWidthDp = hostWidth * mPxToDp;
107 mLastContentHeightDp = hostHeight * mPxToDp;
108 mLastViewportDp.set(0, 0, mLastContentWidthDp, mLastContentHeightDp);
109 mLastVisibleViewportDp.set(0, 0, mLastContentWidthDp, mLastContentHeight Dp);
110 mLastFullscreenViewportDp.set(0, 0, mLastContentWidthDp, mLastContentHei ghtDp);
111
112 mLastHeightMinusTopControlsDp = mLastContentHeightDp;
113 }
114
115 /**
116 * @return The actual current time of the app in ms.
117 */
118 public static long time() {
119 return SystemClock.uptimeMillis();
120 }
121
122 /**
123 * Gives the {@link LayoutManager} a chance to intercept and process touch e vents from the
124 * Android {@link View} system.
125 * @param e The {@link MotionEvent} that might be intercepte d.
126 * @param isKeyboardShowing Whether or not the keyboard is showing.
127 * @return Whether or not this current touch gesture should be intercepted and
128 * continually forwarded to this class.
129 */
130 public boolean onInterceptTouchEvent(MotionEvent e, boolean isKeyboardShowin g) {
131 if (mActiveLayout == null) return false;
132
133 if (e.getAction() == MotionEvent.ACTION_DOWN) {
134 mLastTapX = (int) e.getX();
135 mLastTapY = (int) e.getY();
136 }
137
138 Point offsets = getMotionOffsets(e);
139 mActiveEventFilter =
140 mActiveLayout.findInterceptingEventFilter(e, offsets, isKeyboard Showing);
141 if (mActiveEventFilter != null) mActiveLayout.unstallImmediately();
142 return mActiveEventFilter != null;
143 }
144
145 /**
146 * Gives the {@link LayoutManager} a chance to process the touch events from the Android
147 * {@link View} system.
148 * @param e A {@link MotionEvent} instance.
149 * @return Whether or not {@code e} was consumed.
150 */
151 public boolean onTouchEvent(MotionEvent e) {
152 if (mActiveEventFilter == null) return false;
153
154 boolean consumed = mActiveEventFilter.onTouchEvent(e);
155 Point offsets = getMotionOffsets(e);
156 if (offsets != null) mActiveEventFilter.setCurrentMotionEventOffsets(off sets.x, offsets.y);
157 return consumed;
158 }
159
160 @Override
161 public boolean propagateEvent(MotionEvent e) {
162 if (e == null) return false;
163
164 View view = getActiveLayout().getViewForInteraction();
165 if (view == null) return false;
166
167 return view.dispatchTouchEvent(e);
168 }
169
170 @Override
171 public int getViewportWidth() {
172 return mHost.getWidth();
173 }
174
175 private Point getMotionOffsets(MotionEvent e) {
176 int actionMasked = e.getActionMasked();
177 if (SPenSupport.isSPenSupported(mHost.getContext())) {
178 actionMasked = SPenSupport.convertSPenEventAction(actionMasked);
179 }
180
181 if (actionMasked == MotionEvent.ACTION_DOWN
182 || actionMasked == MotionEvent.ACTION_HOVER_ENTER) {
183 getViewportPixel(mCachedRect);
184
185 mCachedPoint.set(-mCachedRect.left, -mCachedRect.top);
186 return mCachedPoint;
187 } else if (actionMasked == MotionEvent.ACTION_UP
188 || actionMasked == MotionEvent.ACTION_CANCEL
189 || actionMasked == MotionEvent.ACTION_HOVER_EXIT) {
190 mCachedPoint.set(0, 0);
191 return mCachedPoint;
192 }
193
194 return null;
195 }
196
197 /**
198 * Updates the state of the active {@link Layout} if needed. This updates t he animations and
199 * cascades the changes to the tabs.
200 */
201 public void onUpdate() {
202 TraceEvent.begin("LayoutDriver:onUpdate");
203 onUpdate(time(), FRAME_DELTA_TIME_MS);
204 TraceEvent.end("LayoutDriver:onUpdate");
205 }
206
207 /**
208 * Updates the state of the layout.
209 * @param timeMs The time in milliseconds.
210 * @param dtMs The delta time since the last update in milliseconds.
211 * @return Whether or not the {@link LayoutManager} needs more updates .
212 */
213 @VisibleForTesting
214 public boolean onUpdate(long timeMs, long dtMs) {
215 if (!mUpdateRequested) return false;
216 mUpdateRequested = false;
217 final Layout layout = getActiveLayout();
218 if (layout != null && layout.onUpdate(timeMs, dtMs) && layout.isHiding() ) {
219 layout.doneHiding();
220 }
221 return mUpdateRequested;
222 }
223
224 /**
225 * Initializes the {@link LayoutManager}. Must be called before using this object.
226 * @param selector A {@link TabModelSelector} instance.
227 * @param creator A {@link TabCreatorManager} instance.
228 * @param content A {@link TabContentManager} instance.
229 * @param androidContentContainer A {@link ViewGroup} for Android views to be bound to.
230 * @param contextualSearchDelegate A {@link ContextualSearchDelegate} instan ce.
231 * @param dynamicResourceLoader A {@link DynamicResourceLoader} instance.
232 */
233 public void init(TabModelSelector selector, TabCreatorManager creator,
234 TabContentManager content, ViewGroup androidContentContainer,
235 ContextualSearchManagementDelegate contextualSearchDelegate,
236 DynamicResourceLoader dynamicResourceLoader) {
237 mTabModelSelector = selector;
238 mContentContainer = androidContentContainer;
239
240 if (mNextActiveLayout != null) startShowing(mNextActiveLayout, true);
241 }
242
243 /**
244 * Cleans up and destroys this object. It should not be used after this.
245 */
246 public void destroy() {
247 mSceneChangeObservers.clear();
248 }
249
250 /**
251 * @param observer Adds {@code observer} to be notified when the active {@co de Layout} changes.
252 */
253 public void addSceneChangeObserver(SceneChangeObserver observer) {
254 mSceneChangeObservers.addObserver(observer);
255 }
256
257 /**
258 * @param observer Removes {@code observer}.
259 */
260 public void removeSceneChangeObserver(SceneChangeObserver observer) {
261 mSceneChangeObservers.removeObserver(observer);
262 }
263
264 /**
265 * Called when the viewport has been changed. Override this to be notified when
266 * {@link #pushNewViewport(Rect, Rect, int)} calls actually change the curre nt viewport.
267 * @param viewportDp The new viewport in dp.
268 */
269 protected void onViewportChanged(RectF viewportDp) {
270 if (getActiveLayout() != null) {
271 getActiveLayout().sizeChanged(viewportDp, mLastVisibleViewportDp,
272 mLastFullscreenViewportDp, mLastHeightMinusTopControlsDp, ge tOrientation());
273 }
274 }
275
276 /**
277 * Should be called from an external source when the viewport changes. {@co de viewport} and
278 * {@code visibleViewport} are different, as the top controls might be cover ing part of the
279 * viewport but a {@link Layout} might want to consume the whole space (or n ot).
280 * @param viewport The new viewport in px.
281 * @param visibleViewport The new visible viewport in px.
282 * @param heightMinusTopControls The height of the viewport minus the top co ntrols.
283 */
284 public final void pushNewViewport(
285 Rect viewport, Rect visibleViewport, int heightMinusTopControls) {
286 mLastViewportPx.set(viewport);
287 mLastVisibleViewportPx.set(visibleViewport);
288
289 mLastViewportDp.set(viewport.left * mPxToDp, viewport.top * mPxToDp,
290 viewport.right * mPxToDp, viewport.bottom * mPxToDp);
291 mLastVisibleViewportDp.set(visibleViewport.left * mPxToDp, visibleViewpo rt.top * mPxToDp,
292 visibleViewport.right * mPxToDp, visibleViewport.bottom * mPxToD p);
293 mLastFullscreenViewportDp.set(0, 0, viewport.right * mPxToDp, viewport.b ottom * mPxToDp);
294 mLastHeightMinusTopControlsDp = heightMinusTopControls * mPxToDp;
295
296 propagateViewportToActiveLayout();
297 }
298
299 /**
300 * @return The default {@link Layout} to show when {@link Layout}s get hidde n and the next
301 * {@link Layout} to show isn't known.
302 */
303 protected abstract Layout getDefaultLayout();
304
305 // TODO(dtrainor): Remove these from this control class. Split the interfac e?
306 @Override public abstract void initLayoutTabFromHost(final int tabId);
307
308 @Override
309 public abstract LayoutTab createLayoutTab(int id, boolean incognito, boolean showCloseButton,
310 boolean isTitleNeeded, float maxContentWidth, float maxContentHeight );
311
312 @Override public abstract void releaseTabLayout(int id);
313
314 /**
315 * @return The {@link TabModelSelector} instance this class knows about.
316 */
317 protected TabModelSelector getTabModelSelector() {
318 return mTabModelSelector;
319 }
320
321 /**
322 * @return The next {@link Layout} that will be shown. If no {@link Layout} has been set
323 * since the last time {@link #startShowing(Layout, boolean)} was ca lled, this will be
324 * {@link #getDefaultLayout()}.
325 */
326 protected Layout getNextLayout() {
327 return mNextActiveLayout != null ? mNextActiveLayout : getDefaultLayout( );
328 }
329
330 @Override
331 public Layout getActiveLayout() {
332 return mActiveLayout;
333 }
334
335 @Override
336 public RectF getViewportDp(RectF rect) {
337 if (rect == null) rect = new RectF();
338
339 if (getActiveLayout() == null) {
340 rect.set(mLastViewportDp);
341 return rect;
342 }
343
344 final int flags = getActiveLayout().getSizingFlags();
345 if ((flags & SizingFlags.REQUIRE_FULLSCREEN_SIZE) != 0) {
346 rect.set(mLastFullscreenViewportDp);
347 } else if ((flags & SizingFlags.ALLOW_TOOLBAR_HIDE) != 0) {
348 rect.set(mLastViewportDp);
349 } else {
350 rect.set(mLastVisibleViewportDp);
351 }
352
353 return rect;
354 }
355
356 @Override
357 public Rect getViewportPixel(Rect rect) {
358 if (rect == null) rect = new Rect();
359
360 if (getActiveLayout() == null) {
361 rect.set(mLastViewportPx);
362 return rect;
363 }
364
365 final int flags = getActiveLayout().getSizingFlags();
366 if ((flags & SizingFlags.REQUIRE_FULLSCREEN_SIZE) != 0) {
367 rect.set(mLastFullscreenViewportPx);
368 } else if ((flags & SizingFlags.ALLOW_TOOLBAR_HIDE) != 0) {
369 rect.set(mLastViewportPx);
370 } else {
371 rect.set(mLastVisibleViewportPx);
372 }
373 return rect;
374 }
375
376 @Override
377 public ChromeFullscreenManager getFullscreenManager() {
378 return mHost != null ? mHost.getFullscreenManager() : null;
379 }
380
381 @Override
382 public void requestUpdate() {
383 if (!mUpdateRequested) mHost.requestRender();
384 mUpdateRequested = true;
385 }
386
387 @Override
388 public void startHiding(int nextTabId, boolean hintAtTabSelection) {
389 requestUpdate();
390 if (hintAtTabSelection) {
391 for (SceneChangeObserver observer : mSceneChangeObservers) {
392 observer.onTabSelectionHinted(nextTabId);
393 }
394 }
395 }
396
397 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
398 @Override
399 public void doneHiding() {
400 // TODO: If next layout is default layout clear caches (should this be a sub layout thing?)
401
402 assert mNextActiveLayout != null : "Need to have a next active layout.";
403 if (mNextActiveLayout != null) {
404 startShowing(mNextActiveLayout, true);
405 }
406 }
407
408 @Override
409 public void doneShowing() {}
410
411 /**
412 * Should be called by control logic to show a new {@link Layout}.
413 *
414 * TODO(dtrainor, clholgat): Clean up the show logic to guarantee startHidin g/doneHiding get
415 * called.
416 *
417 * @param layout The new {@link Layout} to show.
418 * @param animate Whether or not {@code layout} should animate as it shows.
419 */
420 protected void startShowing(Layout layout, boolean animate) {
421 assert mTabModelSelector != null : "init() must be called first.";
422 assert layout != null : "Can't show a null layout.";
423
424 // Set the new layout
425 setNextLayout(null);
426 Layout oldLayout = getActiveLayout();
427 if (oldLayout != layout) {
428 if (oldLayout != null) {
429 oldLayout.detachViews();
430 }
431 layout.contextChanged(mHost.getContext());
432 layout.attachViews(mContentContainer);
433 mActiveLayout = layout;
434 }
435
436 ChromeFullscreenManager fullscreenManager = mHost.getFullscreenManager() ;
437 if (fullscreenManager != null) {
438 // Release any old fullscreen token we were holding.
439 fullscreenManager.hideControlsPersistent(mFullscreenToken);
440 mFullscreenToken = FullscreenManager.INVALID_TOKEN;
441
442 // Grab a new fullscreen token if this layout can't be in fullscreen .
443 final int flags = getActiveLayout().getSizingFlags();
444 if ((flags & SizingFlags.ALLOW_TOOLBAR_HIDE) == 0) {
445 mFullscreenToken = fullscreenManager.showControlsPersistent();
446 }
447
448 // Hide the toolbar immediately if the layout wants it gone quickly.
449 fullscreenManager.setTopControlsPermamentlyHidden(
450 flags == SizingFlags.HELPER_HIDE_TOOLBAR_IMMEDIATE);
451 }
452
453 propagateViewportToActiveLayout();
454 getActiveLayout().show(time(), animate);
455 mHost.setContentOverlayVisibility(getActiveLayout().shouldDisplayContent Overlay());
456 mHost.requestRender();
457
458 // Notify observers about the new scene.
459 for (SceneChangeObserver observer : mSceneChangeObservers) {
460 observer.onSceneChange(getActiveLayout());
461 }
462 }
463
464 /**
465 * Sets the next {@link Layout} to show after the current {@link Layout} is finished and is done
466 * hiding.
467 * @param layout The new {@link Layout} to show.
468 */
469 public void setNextLayout(Layout layout) {
470 mNextActiveLayout = (layout == null) ? getDefaultLayout() : layout;
471 }
472
473 @Override
474 public boolean isActiveLayout(Layout layout) {
475 return layout == mActiveLayout;
476 }
477
478 /**
479 * Get a list of virtual views for accessibility.
480 *
481 * @param views A List to populate with virtual views.
482 */
483 public abstract void getVirtualViews(List<VirtualView> views);
484
485 /**
486 * @return The {@link EdgeSwipeHandler} responsible for processing swipe eve nts for the toolbar.
487 */
488 public abstract EdgeSwipeHandler getTopSwipeHandler();
489
490 /**
491 * Should be called when the user presses the back button on the phone.
492 * @return Whether or not the back button was consumed by the active {@link Layout}.
493 */
494 public abstract boolean onBackPressed();
495
496 private void propagateViewportToActiveLayout() {
497 getViewportDp(mCachedRectF);
498
499 float width = mCachedRectF.width();
500 float height = mCachedRectF.height();
501 mLastContentWidthDp = width;
502 mLastContentHeightDp = height;
503 onViewportChanged(mCachedRectF);
504 }
505
506 private int getOrientation() {
507 if (mLastContentWidthDp > mLastContentHeightDp) {
508 return Orientation.LANDSCAPE;
509 } else {
510 return Orientation.PORTRAIT;
511 }
512 }
513 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698