Commit c66df030 authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] Decouple *Controller classes from Mediator

Break cyclic dependency of PlayerFrameMediator with
- PlayerFrameScaleController
- PlayerFrameScrollController

BitmapState is tightly coupled to PlayerFrameMediator with good reason
so a cyclic dependency there is somewhat unavoidable.

This is achieved by having PlayerFrameCoordinator instantiate
everything and then introducing a new class that handles dispatch of
gestures. A helper for scaling is also added to break the two-way
interdependence that existed in the mediator.

Bug: 1099722
Change-Id: I13b258d973a5ff81cdf75505f59aabb02d66a6c6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2295751
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: default avatarMehran Mahmoudi <mahmoudi@chromium.org>
Reviewed-by: default avatarFred Mello <fredmello@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789996}
parent 99ad7711
...@@ -61,6 +61,7 @@ android_library("java") { ...@@ -61,6 +61,7 @@ android_library("java") {
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetectorDelegate.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorDelegate.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorDelegate.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameProperties.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameProperties.java",
......
...@@ -6,6 +6,7 @@ package org.chromium.components.paintpreview.player.frame; ...@@ -6,6 +6,7 @@ package org.chromium.components.paintpreview.player.frame;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.Size;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.widget.OverScroller; import android.widget.OverScroller;
...@@ -37,12 +38,24 @@ public class PlayerFrameCoordinator { ...@@ -37,12 +38,24 @@ public class PlayerFrameCoordinator {
PropertyModel model = new PropertyModel.Builder(PlayerFrameProperties.ALL_KEYS).build(); PropertyModel model = new PropertyModel.Builder(PlayerFrameProperties.ALL_KEYS).build();
OverScroller scroller = new OverScroller(context); OverScroller scroller = new OverScroller(context);
scroller.setFriction(ViewConfiguration.getScrollFriction() / 2); scroller.setFriction(ViewConfiguration.getScrollFriction() / 2);
mMediator = new PlayerFrameMediator(model, compositorDelegate, new PlayerFrameViewport(),
scroller, gestureHandler, frameGuid, contentWidth, contentHeight, initialScrollX, mMediator = new PlayerFrameMediator(model, compositorDelegate, gestureHandler, frameGuid,
initialScrollY); new Size(contentWidth, contentHeight), initialScrollX, initialScrollY);
mView = new PlayerFrameView(context, canDetectZoom, mMediator);
PlayerFrameScaleController scaleController = null;
if (canDetectZoom) {
scaleController =
new PlayerFrameScaleController(model.get(PlayerFrameProperties.SCALE_MATRIX),
mMediator, gestureHandler::onScale);
}
PlayerFrameScrollController scrollController = new PlayerFrameScrollController(
scroller, mMediator, gestureHandler::onScroll, gestureHandler::onFling);
PlayerFrameGestureDetectorDelegate gestureDelegate = new PlayerFrameGestureDetectorDelegate(
scaleController, scrollController, mMediator);
mView = new PlayerFrameView(context, canDetectZoom, mMediator, gestureDelegate);
if (overscrollHandler != null) { if (overscrollHandler != null) {
mMediator.setOverscrollHandler(overscrollHandler); scrollController.setOverscrollHandler(overscrollHandler);
} }
PropertyModelChangeProcessor.create(model, mView, PlayerFrameViewBinder::bind); PropertyModelChangeProcessor.create(model, mView, PlayerFrameViewBinder::bind);
} }
......
...@@ -11,14 +11,14 @@ import android.view.ScaleGestureDetector; ...@@ -11,14 +11,14 @@ import android.view.ScaleGestureDetector;
/** /**
* Detects scroll, fling, and scale gestures on calls to {@link #onTouchEvent} and reports back to * Detects scroll, fling, and scale gestures on calls to {@link #onTouchEvent} and reports back to
* the provided {@link PlayerFrameViewDelegate}. * the provided {@link PlayerFrameGestureDetectorDelegate}.
*/ */
class PlayerFrameGestureDetector class PlayerFrameGestureDetector
implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener { implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener {
private GestureDetector mGestureDetector; private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector; private ScaleGestureDetector mScaleGestureDetector;
private boolean mCanDetectZoom; private boolean mCanDetectZoom;
private PlayerFrameViewDelegate mPlayerFrameViewDelegate; private PlayerFrameGestureDetectorDelegate mDelegate;
private PlayerFrameGestureDetector mParentGestureDetector; private PlayerFrameGestureDetector mParentGestureDetector;
/** /**
* Last horizontal scroll distance that was detected by this {@link PlayerFrameGestureDetector} * Last horizontal scroll distance that was detected by this {@link PlayerFrameGestureDetector}
...@@ -36,14 +36,14 @@ class PlayerFrameGestureDetector ...@@ -36,14 +36,14 @@ class PlayerFrameGestureDetector
* {@link ScaleGestureDetector}. * {@link ScaleGestureDetector}.
* @param canDetectZoom Whether this {@link PlayerFrameGestureDetector} should detect scale * @param canDetectZoom Whether this {@link PlayerFrameGestureDetector} should detect scale
* gestures. * gestures.
* @param playerFrameViewDelegate The delegate used when desired gestured are detected. * @param delegate The delegate used when desired gestured are detected.
*/ */
PlayerFrameGestureDetector(Context context, boolean canDetectZoom, PlayerFrameGestureDetector(
PlayerFrameViewDelegate playerFrameViewDelegate) { Context context, boolean canDetectZoom, PlayerFrameGestureDetectorDelegate delegate) {
mGestureDetector = new GestureDetector(context, this); mGestureDetector = new GestureDetector(context, this);
mScaleGestureDetector = new ScaleGestureDetector(context, this); mScaleGestureDetector = new ScaleGestureDetector(context, this);
mCanDetectZoom = canDetectZoom; mCanDetectZoom = canDetectZoom;
mPlayerFrameViewDelegate = playerFrameViewDelegate; mDelegate = delegate;
} }
/** /**
...@@ -65,7 +65,7 @@ class PlayerFrameGestureDetector ...@@ -65,7 +65,7 @@ class PlayerFrameGestureDetector
} }
if (event.getAction() == MotionEvent.ACTION_UP) { if (event.getAction() == MotionEvent.ACTION_UP) {
mPlayerFrameViewDelegate.onRelease(); mDelegate.onRelease();
// Propagate the release to the parent, this won't trigger any unexpected behavior as // Propagate the release to the parent, this won't trigger any unexpected behavior as
// this is only an UP event. // this is only an UP event.
if (mParentGestureDetector != null) { if (mParentGestureDetector != null) {
...@@ -85,13 +85,13 @@ class PlayerFrameGestureDetector ...@@ -85,13 +85,13 @@ class PlayerFrameGestureDetector
@Override @Override
public boolean onSingleTapUp(MotionEvent e) { public boolean onSingleTapUp(MotionEvent e) {
mPlayerFrameViewDelegate.onTap((int) e.getX(), (int) e.getY()); mDelegate.onTap((int) e.getX(), (int) e.getY());
return true; return true;
} }
@Override @Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (mPlayerFrameViewDelegate.scrollBy(distanceX, distanceY)) { if (mDelegate.scrollBy(distanceX, distanceY)) {
mLastParentScrollX = 0f; mLastParentScrollX = 0f;
mLastParentScrollY = 0f; mLastParentScrollY = 0f;
return true; return true;
...@@ -116,12 +116,12 @@ class PlayerFrameGestureDetector ...@@ -116,12 +116,12 @@ class PlayerFrameGestureDetector
@Override @Override
public void onLongPress(MotionEvent e) { public void onLongPress(MotionEvent e) {
mPlayerFrameViewDelegate.onLongPress((int) e.getX(), (int) e.getY()); mDelegate.onLongPress((int) e.getX(), (int) e.getY());
} }
@Override @Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mPlayerFrameViewDelegate.onFling(velocityX, velocityY)) return true; if (mDelegate.onFling(velocityX, velocityY)) return true;
if (mParentGestureDetector != null) { if (mParentGestureDetector != null) {
return mParentGestureDetector.onFling(e1, e2, velocityX, velocityY); return mParentGestureDetector.onFling(e1, e2, velocityX, velocityY);
...@@ -132,7 +132,7 @@ class PlayerFrameGestureDetector ...@@ -132,7 +132,7 @@ class PlayerFrameGestureDetector
@Override @Override
public boolean onScale(ScaleGestureDetector detector) { public boolean onScale(ScaleGestureDetector detector) {
assert mCanDetectZoom; assert mCanDetectZoom;
return mPlayerFrameViewDelegate.scaleBy( return mDelegate.scaleBy(
detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
} }
...@@ -145,7 +145,7 @@ class PlayerFrameGestureDetector ...@@ -145,7 +145,7 @@ class PlayerFrameGestureDetector
@Override @Override
public void onScaleEnd(ScaleGestureDetector detector) { public void onScaleEnd(ScaleGestureDetector detector) {
assert mCanDetectZoom; assert mCanDetectZoom;
mPlayerFrameViewDelegate.scaleFinished( mDelegate.scaleFinished(
detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
} }
} }
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.paintpreview.player.frame;
/**
* Dispatches gesture events to the correct controllers.
*/
public class PlayerFrameGestureDetectorDelegate {
private final PlayerFrameScaleController mScaleController;
private final PlayerFrameScrollController mScrollController;
private final PlayerFrameViewDelegate mViewDelegate;
PlayerFrameGestureDetectorDelegate(PlayerFrameScaleController scaleController,
PlayerFrameScrollController scrollController, PlayerFrameViewDelegate viewDelegate) {
mScaleController = scaleController;
mScrollController = scrollController;
mViewDelegate = viewDelegate;
}
/**
* Called when a scroll gesture is performed.
* @param distanceX Horizontal scroll values in pixels.
* @param distanceY Vertical scroll values in pixels.
* @return Whether this scroll event was consumed.
*/
boolean scrollBy(float distanceX, float distanceY) {
return mScrollController.scrollBy(distanceX, distanceY);
}
/**
* Called when a fling gesture is performed.
* @param velocityX Horizontal velocity value in pixels.
* @param velocityY Vertical velocity value in pixels.
* @return Whether this fling was consumed.
*/
boolean onFling(float velocityX, float velocityY) {
return mScrollController.onFling(velocityX, velocityY);
}
/**
* Called when a gesture is released.
*/
void onRelease() {
mScrollController.onRelease();
}
/**
* Called when a scale gesture is performed.
* @return Whether this scale event was consumed.
*/
boolean scaleBy(float scaleFactor, float focalPointX, float focalPointY) {
return mScaleController.scaleBy(scaleFactor, focalPointX, focalPointY);
}
/**
* Called when a scale gesture is finished.
* @return Whether this scale event was consumed.
*/
boolean scaleFinished(float scaleFactor, float focalPointX, float focalPointY) {
return mScaleController.scaleFinished(scaleFactor, focalPointX, focalPointY);
}
/**
* Called when a single tap gesture is performed.
* @param x X coordinate of the point clicked.
* @param y Y coordinate of the point clicked.
*/
void onTap(int x, int y) {
mViewDelegate.onTap(x, y);
}
/**
* Called when a long press gesture is performed.
* @param x X coordinate of the point clicked.
* @param y Y coordinate of the point clicked.
*/
void onLongPress(int x, int y) {
mViewDelegate.onLongPress(x, y);
}
}
...@@ -9,12 +9,10 @@ import android.graphics.Matrix; ...@@ -9,12 +9,10 @@ import android.graphics.Matrix;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.Size; import android.util.Size;
import android.view.View; import android.view.View;
import android.widget.OverScroller;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.UnguessableToken; import org.chromium.base.UnguessableToken;
import org.chromium.components.paintpreview.player.OverscrollHandler;
import org.chromium.components.paintpreview.player.PlayerCompositorDelegate; import org.chromium.components.paintpreview.player.PlayerCompositorDelegate;
import org.chromium.components.paintpreview.player.PlayerGestureListener; import org.chromium.components.paintpreview.player.PlayerGestureListener;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -64,36 +62,29 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -64,36 +62,29 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
/** The viewport of this frame. */ /** The viewport of this frame. */
private final PlayerFrameViewport mViewport; private final PlayerFrameViewport mViewport;
private float mInitialScaleFactor;
/** Handles scaling of bitmaps. */ /** Handles scaling of bitmaps. */
private final Matrix mBitmapScaleMatrix = new Matrix(); private final Matrix mBitmapScaleMatrix;
/** Handles scrolling. */
private final PlayerFrameScrollController mScrollController;
/** Handles scaling. */
private final PlayerFrameScaleController mScaleController;
private final PlayerFrameBitmapStateController mBitmapStateController; private final PlayerFrameBitmapStateController mBitmapStateController;
private PlayerGestureListener mGestureListener; private PlayerGestureListener mGestureListener;
PlayerFrameMediator(PropertyModel model, PlayerCompositorDelegate compositorDelegate, PlayerFrameMediator(PropertyModel model, PlayerCompositorDelegate compositorDelegate,
PlayerFrameViewport viewport, OverScroller scroller, PlayerGestureListener gestureListener, UnguessableToken frameGuid, Size contentSize,
PlayerGestureListener gestureListener, UnguessableToken frameGuid, int contentWidth, int initialScrollX, int initialScrollY) {
int contentHeight, int initialScrollX, int initialScrollY) { mBitmapScaleMatrix = new Matrix();
mModel = model; mModel = model;
mModel.set(PlayerFrameProperties.SCALE_MATRIX, mBitmapScaleMatrix); mModel.set(PlayerFrameProperties.SCALE_MATRIX, mBitmapScaleMatrix);
mCompositorDelegate = compositorDelegate; mCompositorDelegate = compositorDelegate;
mViewport = viewport; mGestureListener = gestureListener;
mViewport = new PlayerFrameViewport();
mInitialScaleFactor = 0f;
mGuid = frameGuid; mGuid = frameGuid;
mContentSize = new Size(contentWidth, contentHeight); mContentSize = contentSize;
mBitmapStateController = new PlayerFrameBitmapStateController( mBitmapStateController = new PlayerFrameBitmapStateController(
mGuid, mViewport, mContentSize, mCompositorDelegate, this); mGuid, mViewport, mContentSize, mCompositorDelegate, this);
mScrollController = new PlayerFrameScrollController(scroller, mViewport, mContentSize, this,
gestureListener::onScroll, gestureListener::onFling);
mScaleController = new PlayerFrameScaleController(
mViewport, mContentSize, mBitmapScaleMatrix, this, gestureListener::onScale);
mGestureListener = gestureListener;
mViewport.offset(initialScrollX, initialScrollY); mViewport.offset(initialScrollX, initialScrollY);
mViewport.setScale(0f); mViewport.setScale(0f);
} }
...@@ -143,15 +134,6 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -143,15 +134,6 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
setBitmapScaleMatrix(matrix, scaleFactor); setBitmapScaleMatrix(matrix, scaleFactor);
} }
/**
* Sets the overscroll-to-refresh handler on the {@link mScrollController}. This cannot be
* created at construction of this object as it needs to be created on top of the view
* hierarchy to show the animation.
*/
void setOverscrollHandler(OverscrollHandler overscrollHandler) {
mScrollController.setOverscrollHandler(overscrollHandler);
}
// PlayerFrameViewDelegate // PlayerFrameViewDelegate
@Override @Override
...@@ -163,35 +145,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -163,35 +145,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
} }
// Set initial scale so that content width fits within the layout dimensions. // Set initial scale so that content width fits within the layout dimensions.
mScaleController.calculateInitialScaleFactor(width); adjustInitialScaleFactor(width);
final float scaleFactor = mViewport.getScale(); final float scaleFactor = mViewport.getScale();
updateViewportSize(width, height, updateViewportSize(
(scaleFactor == 0f) ? mScaleController.getInitialScaleFactor() : scaleFactor); width, height, (scaleFactor == 0f) ? getInitialScaleFactor() : scaleFactor);
}
@Override
public boolean scrollBy(float distanceX, float distanceY) {
return mScrollController.scrollBy(distanceX, distanceY);
}
@Override
public boolean onFling(float velocityX, float velocityY) {
return mScrollController.onFling(velocityX, velocityY);
}
@Override
public void onRelease() {
mScrollController.onRelease();
}
@Override
public boolean scaleBy(float scaleFactor, float focalPointX, float focalPointY) {
return mScaleController.scaleBy(scaleFactor, focalPointX, focalPointY);
}
@Override
public boolean scaleFinished(float scaleFactor, float focalPointX, float focalPointY) {
return mScaleController.scaleFinished(scaleFactor, focalPointX, focalPointY);
} }
@Override @Override
...@@ -212,6 +169,21 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -212,6 +169,21 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
// PlayerFrameMediatorDelegate // PlayerFrameMediatorDelegate
@Override
public PlayerFrameViewport getViewport() {
return mViewport;
}
@Override
public Size getContentSize() {
return mContentSize;
}
@Override
public float getInitialScaleFactor() {
return mInitialScaleFactor;
}
@Override @Override
public void onStartScaling() { public void onStartScaling() {
mBitmapStateController.invalidateLoadingBitmaps(); mBitmapStateController.invalidateLoadingBitmaps();
...@@ -342,10 +314,9 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -342,10 +314,9 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
@VisibleForTesting @VisibleForTesting
void forceRedraw() { void forceRedraw() {
mScaleController.calculateInitialScaleFactor(mViewport.getWidth()); adjustInitialScaleFactor(mViewport.getWidth());
final float scaleFactor = mViewport.getScale(); final float scaleFactor = mViewport.getScale();
mViewport.setScale( mViewport.setScale((scaleFactor == 0f) ? getInitialScaleFactor() : scaleFactor);
(scaleFactor == 0f) ? mScaleController.getInitialScaleFactor() : scaleFactor);
updateVisuals(true); updateVisuals(true);
for (int i = 0; i < mSubFrameViews.size(); i++) { for (int i = 0; i < mSubFrameViews.size(); i++) {
if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue; if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue;
...@@ -360,4 +331,12 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -360,4 +331,12 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
(int) (((float) inRect.right) * scaleFactor), (int) (((float) inRect.right) * scaleFactor),
(int) (((float) inRect.bottom) * scaleFactor)); (int) (((float) inRect.bottom) * scaleFactor));
} }
/**
* Calculates the initial scale factor for a given viewport width.
* @param width The viewport width.
*/
private void adjustInitialScaleFactor(float width) {
mInitialScaleFactor = width / ((float) mContentSize.getWidth());
}
} }
...@@ -7,11 +7,27 @@ package org.chromium.components.paintpreview.player.frame; ...@@ -7,11 +7,27 @@ package org.chromium.components.paintpreview.player.frame;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.Size;
/** /**
* API of the PlayerFrameMediator to helper classes. * API of the PlayerFrameMediator to helper classes.
*/ */
public interface PlayerFrameMediatorDelegate { public interface PlayerFrameMediatorDelegate {
/**
* Gets the visual viewport of the player.
*/
public PlayerFrameViewport getViewport();
/**
* Gets the size of the content shown in the mediator.
*/
public Size getContentSize();
/**
* Gets the initial scale factor at the last computed viewport width.
*/
public float getInitialScaleFactor();
/** /**
* Triggers an update of the visual contents of the PlayerFrameView. This fetches updates the * Triggers an update of the visual contents of the PlayerFrameView. This fetches updates the
* model and fetches any new bitmaps asynchronously. * model and fetches any new bitmaps asynchronously.
......
...@@ -18,7 +18,6 @@ import org.chromium.base.Callback; ...@@ -18,7 +18,6 @@ import org.chromium.base.Callback;
public class PlayerFrameScaleController { public class PlayerFrameScaleController {
private static final float MAX_SCALE_FACTOR = 5f; private static final float MAX_SCALE_FACTOR = 5f;
private float mInitialScaleFactor;
private float mUncommittedScaleFactor; private float mUncommittedScaleFactor;
/** References to shared state. */ /** References to shared state. */
...@@ -29,31 +28,17 @@ public class PlayerFrameScaleController { ...@@ -29,31 +28,17 @@ public class PlayerFrameScaleController {
private final PlayerFrameMediatorDelegate mMediatorDelegate; private final PlayerFrameMediatorDelegate mMediatorDelegate;
private final Callback<Boolean> mOnScaleListener; private final Callback<Boolean> mOnScaleListener;
PlayerFrameScaleController(PlayerFrameViewport viewport, Size contentSize, PlayerFrameScaleController(Matrix bitmapScaleMatrix,
Matrix bitmapScaleMatrix, PlayerFrameMediatorDelegate mediatorDelegate, PlayerFrameMediatorDelegate mediatorDelegate,
@Nullable Callback<Boolean> onScaleListener) { @Nullable Callback<Boolean> onScaleListener) {
mViewport = viewport; mUncommittedScaleFactor = 0f;
mContentSize = contentSize; mViewport = mediatorDelegate.getViewport();
mContentSize = mediatorDelegate.getContentSize();
mBitmapScaleMatrix = bitmapScaleMatrix; mBitmapScaleMatrix = bitmapScaleMatrix;
mMediatorDelegate = mediatorDelegate; mMediatorDelegate = mediatorDelegate;
mOnScaleListener = onScaleListener; mOnScaleListener = onScaleListener;
} }
/**
* Calculates the initial scale factor for a given viewport width.
* @param width The viewport width.
*/
void calculateInitialScaleFactor(float width) {
mInitialScaleFactor = width / ((float) mContentSize.getWidth());
}
/**
* Gets the initial scale factor at the last computed viewport width.
*/
float getInitialScaleFactor() {
return mInitialScaleFactor;
}
/** /**
* How scale for the paint preview player works. * How scale for the paint preview player works.
* *
...@@ -92,22 +77,23 @@ public class PlayerFrameScaleController { ...@@ -92,22 +77,23 @@ public class PlayerFrameScaleController {
} }
// Don't scale outside of the acceptable range. The value is still accumulated such that the // Don't scale outside of the acceptable range. The value is still accumulated such that the
// continuous gesture feels smooth. // continuous gesture feels smooth.
final float initialScaleFactor = mMediatorDelegate.getInitialScaleFactor();
final float lastUncommittedScaleFactor = mUncommittedScaleFactor; final float lastUncommittedScaleFactor = mUncommittedScaleFactor;
mUncommittedScaleFactor *= scaleFactor; mUncommittedScaleFactor *= scaleFactor;
// Compute a corrected and bounded scale factor when close to the max/min scale. // Compute a corrected and bounded scale factor when close to the max/min scale.
if (mUncommittedScaleFactor < mInitialScaleFactor if (mUncommittedScaleFactor < initialScaleFactor
&& lastUncommittedScaleFactor > mInitialScaleFactor) { && lastUncommittedScaleFactor > initialScaleFactor) {
scaleFactor = mInitialScaleFactor / lastUncommittedScaleFactor; scaleFactor = initialScaleFactor / lastUncommittedScaleFactor;
} else if (mUncommittedScaleFactor > MAX_SCALE_FACTOR } else if (mUncommittedScaleFactor > MAX_SCALE_FACTOR
&& lastUncommittedScaleFactor < MAX_SCALE_FACTOR) { && lastUncommittedScaleFactor < MAX_SCALE_FACTOR) {
scaleFactor = MAX_SCALE_FACTOR / lastUncommittedScaleFactor; scaleFactor = MAX_SCALE_FACTOR / lastUncommittedScaleFactor;
} else if (mUncommittedScaleFactor > mInitialScaleFactor } else if (mUncommittedScaleFactor > initialScaleFactor
&& lastUncommittedScaleFactor < mInitialScaleFactor) { && lastUncommittedScaleFactor < initialScaleFactor) {
scaleFactor = mUncommittedScaleFactor / mInitialScaleFactor; scaleFactor = mUncommittedScaleFactor / initialScaleFactor;
} else if (mUncommittedScaleFactor < MAX_SCALE_FACTOR } else if (mUncommittedScaleFactor < MAX_SCALE_FACTOR
&& lastUncommittedScaleFactor > MAX_SCALE_FACTOR) { && lastUncommittedScaleFactor > MAX_SCALE_FACTOR) {
scaleFactor = mUncommittedScaleFactor / MAX_SCALE_FACTOR; scaleFactor = mUncommittedScaleFactor / MAX_SCALE_FACTOR;
} else if (mUncommittedScaleFactor < mInitialScaleFactor } else if (mUncommittedScaleFactor < initialScaleFactor
|| lastUncommittedScaleFactor > MAX_SCALE_FACTOR) { || lastUncommittedScaleFactor > MAX_SCALE_FACTOR) {
return true; return true;
} }
......
...@@ -32,12 +32,11 @@ public class PlayerFrameScrollController { ...@@ -32,12 +32,11 @@ public class PlayerFrameScrollController {
private final Runnable mOnScrollListener; private final Runnable mOnScrollListener;
private final Runnable mOnFlingListener; private final Runnable mOnFlingListener;
PlayerFrameScrollController(OverScroller scroller, PlayerFrameViewport viewport, PlayerFrameScrollController(OverScroller scroller, PlayerFrameMediatorDelegate mediatorDelegate,
Size contentSize, PlayerFrameMediatorDelegate mediatorDelegate,
@Nullable Runnable onScrollListener, @Nullable Runnable onFlingListener) { @Nullable Runnable onScrollListener, @Nullable Runnable onFlingListener) {
mScroller = scroller; mScroller = scroller;
mViewport = viewport; mViewport = mediatorDelegate.getViewport();
mContentSize = contentSize; mContentSize = mediatorDelegate.getContentSize();
mMediatorDelegate = mediatorDelegate; mMediatorDelegate = mediatorDelegate;
mOnScrollListener = onScrollListener; mOnScrollListener = onScrollListener;
mOnFlingListener = onFlingListener; mOnFlingListener = onFlingListener;
......
...@@ -38,13 +38,14 @@ class PlayerFrameView extends FrameLayout { ...@@ -38,13 +38,14 @@ class PlayerFrameView extends FrameLayout {
* @param playerFrameViewDelegate The interface used for forwarding events. * @param playerFrameViewDelegate The interface used for forwarding events.
*/ */
PlayerFrameView(@NonNull Context context, boolean canDetectZoom, PlayerFrameView(@NonNull Context context, boolean canDetectZoom,
PlayerFrameViewDelegate playerFrameViewDelegate) { PlayerFrameViewDelegate playerFrameViewDelegate,
PlayerFrameGestureDetectorDelegate gestureDetectorDelegate) {
super(context); super(context);
setWillNotDraw(false); setWillNotDraw(false);
mDelegate = playerFrameViewDelegate; mDelegate = playerFrameViewDelegate;
mBitmapPainter = new PlayerFrameBitmapPainter(this::invalidate); mBitmapPainter = new PlayerFrameBitmapPainter(this::invalidate);
mGestureDetector = mGestureDetector =
new PlayerFrameGestureDetector(context, canDetectZoom, playerFrameViewDelegate); new PlayerFrameGestureDetector(context, canDetectZoom, gestureDetectorDelegate);
} }
PlayerFrameGestureDetector getGestureDetector() { PlayerFrameGestureDetector getGestureDetector() {
......
...@@ -13,26 +13,6 @@ interface PlayerFrameViewDelegate { ...@@ -13,26 +13,6 @@ interface PlayerFrameViewDelegate {
*/ */
void setLayoutDimensions(int width, int height); void setLayoutDimensions(int width, int height);
/**
* Called when a scroll gesture is performed.
* @param distanceX Horizontal scroll values in pixels.
* @param distanceY Vertical scroll values in pixels.
* @return Whether this scroll event was consumed.
*/
boolean scrollBy(float distanceX, float distanceY);
/**
* Called when a scale gesture is performed.
* @return Whether this scale event was consumed.
*/
boolean scaleBy(float scaleFactor, float focalPointX, float focalPointY);
/**
* Called when a scale gesture is finished.
* @return Whether this scale event was consumed.
*/
boolean scaleFinished(float scaleFactor, float focalPointX, float focalPointY);
/** /**
* Called when a single tap gesture is performed. * Called when a single tap gesture is performed.
* @param x X coordinate of the point clicked. * @param x X coordinate of the point clicked.
...@@ -46,17 +26,4 @@ interface PlayerFrameViewDelegate { ...@@ -46,17 +26,4 @@ interface PlayerFrameViewDelegate {
* @param y Y coordinate of the point clicked. * @param y Y coordinate of the point clicked.
*/ */
void onLongPress(int x, int y); void onLongPress(int x, int y);
/**
* Called when a fling gesture is performed.
* @param velocityX Horizontal velocity value in pixels.
* @param velocityY Vertical velocity value in pixels.
* @return Whether this fling was consumed.
*/
boolean onFling(float velocityX, float velocityY);
/**
* Called when a gesture is released.
*/
void onRelease();
} }
...@@ -15,6 +15,7 @@ import android.graphics.Matrix; ...@@ -15,6 +15,7 @@ import android.graphics.Matrix;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Parcel; import android.os.Parcel;
import android.util.Pair; import android.util.Pair;
import android.util.Size;
import android.view.View; import android.view.View;
import android.widget.OverScroller; import android.widget.OverScroller;
...@@ -62,9 +63,10 @@ public class PlayerFrameMediatorTest { ...@@ -62,9 +63,10 @@ public class PlayerFrameMediatorTest {
private OverScroller mScroller; private OverScroller mScroller;
private boolean mHasUserInteraction; private boolean mHasUserInteraction;
private PlayerGestureListener mGestureListener; private PlayerGestureListener mGestureListener;
private PlayerFrameViewport mViewport;
private PlayerFrameMediator mMediator; private PlayerFrameMediator mMediator;
private PlayerFrameBitmapStateController mBitmapStateController; private PlayerFrameBitmapStateController mBitmapStateController;
private PlayerFrameScrollController mScrollController;
private PlayerFrameScaleController mScaleController;
/** /**
* Generate an UnguessableToken with a static value. * Generate an UnguessableToken with a static value.
...@@ -207,9 +209,14 @@ public class PlayerFrameMediatorTest { ...@@ -207,9 +209,14 @@ public class PlayerFrameMediatorTest {
mCompositorDelegate = new TestPlayerCompositorDelegate(); mCompositorDelegate = new TestPlayerCompositorDelegate();
mScroller = new OverScroller(ContextUtils.getApplicationContext()); mScroller = new OverScroller(ContextUtils.getApplicationContext());
mGestureListener = new PlayerGestureListener(null, () -> mHasUserInteraction = true); mGestureListener = new PlayerGestureListener(null, () -> mHasUserInteraction = true);
mViewport = new PlayerFrameViewport(); Size contentSize = new Size(CONTENT_WIDTH, CONTENT_HEIGHT);
mMediator = new PlayerFrameMediator(mModel, mCompositorDelegate, mViewport, mScroller, mMediator = new PlayerFrameMediator(
mGestureListener, mFrameGuid, CONTENT_WIDTH, CONTENT_HEIGHT, 0, 0); mModel, mCompositorDelegate, mGestureListener, mFrameGuid, contentSize, 0, 0);
mScaleController =
new PlayerFrameScaleController(mModel.get(PlayerFrameProperties.SCALE_MATRIX),
mMediator, mGestureListener::onScale);
mScrollController = new PlayerFrameScrollController(
mScroller, mMediator, mGestureListener::onScroll, mGestureListener::onFling);
mBitmapStateController = mMediator.getBitmapStateControllerForTest(); mBitmapStateController = mMediator.getBitmapStateControllerForTest();
} }
...@@ -305,7 +312,7 @@ public class PlayerFrameMediatorTest { ...@@ -305,7 +312,7 @@ public class PlayerFrameMediatorTest {
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
mMediator.scrollBy(10, 20); mScrollController.scrollBy(10, 20);
// The view port was moved with the #updateViewport call. It should've been updated in the // The view port was moved with the #updateViewport call. It should've been updated in the
// model. // model.
Rect expectedViewPort = new Rect(10, 20, 110, 220); Rect expectedViewPort = new Rect(10, 20, 110, 220);
...@@ -343,7 +350,7 @@ public class PlayerFrameMediatorTest { ...@@ -343,7 +350,7 @@ public class PlayerFrameMediatorTest {
// Move the view port slightly. It is still covered by the same 4 tiles. Since there were // Move the view port slightly. It is still covered by the same 4 tiles. Since there were
// already bitmap requests out for those tiles and their adjacent tiles, we shouldn't have // already bitmap requests out for those tiles and their adjacent tiles, we shouldn't have
// made new requests. // made new requests.
mMediator.scrollBy(10, 20); mScrollController.scrollBy(10, 20);
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
// Move the view port to the bottom right so it covers portions of the 4 bottom right bitmap // Move the view port to the bottom right so it covers portions of the 4 bottom right bitmap
...@@ -362,7 +369,7 @@ public class PlayerFrameMediatorTest { ...@@ -362,7 +369,7 @@ public class PlayerFrameMediatorTest {
// | | | | 6 | 1 | 3 | // | | | | 6 | 1 | 3 |
// ------------------------- // -------------------------
// | | | | 7 | 2 | 4 | // | | | | 7 | 2 | 4 |
mMediator.scrollBy(430, 900); mScrollController.scrollBy(430, 900);
expectedViewPort.set(450, 940, 550, 1140); expectedViewPort.set(450, 940, 550, 1140);
Assert.assertEquals(expectedViewPort, mModel.get(PlayerFrameProperties.VIEWPORT)); Assert.assertEquals(expectedViewPort, mModel.get(PlayerFrameProperties.VIEWPORT));
...@@ -418,7 +425,7 @@ public class PlayerFrameMediatorTest { ...@@ -418,7 +425,7 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(Arrays.deepEquals( Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest())); expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
mMediator.scrollBy(10, 15); mScrollController.scrollBy(10, 15);
// The current viewport covers portions of the 4 top left bitmap tiles. // The current viewport covers portions of the 4 top left bitmap tiles.
// ------------------------- // -------------------------
// | x | x | x | | | | // | x | x | x | | | |
...@@ -440,7 +447,7 @@ public class PlayerFrameMediatorTest { ...@@ -440,7 +447,7 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(Arrays.deepEquals( Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest())); expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
mMediator.scrollBy(200, 400); mScrollController.scrollBy(200, 400);
// The current view port contains portions of the middle 4 tiles. // The current view port contains portions of the middle 4 tiles.
// Tiles marked with x are required for the current view port. // Tiles marked with x are required for the current view port.
// ------------------------- // -------------------------
...@@ -474,7 +481,7 @@ public class PlayerFrameMediatorTest { ...@@ -474,7 +481,7 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(Arrays.deepEquals( Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest())); expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
mMediator.scrollBy(200, 400); mScrollController.scrollBy(200, 400);
// The current view port contains portions of the 4 bottom right tiles. // The current view port contains portions of the 4 bottom right tiles.
// Tiles marked with x are required for the current view port. // Tiles marked with x are required for the current view port.
// ------------------------- // -------------------------
...@@ -543,7 +550,7 @@ public class PlayerFrameMediatorTest { ...@@ -543,7 +550,7 @@ public class PlayerFrameMediatorTest {
expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX))); expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX)));
// Move the viewport to an area that is covered by 4 top left tiles. // Move the viewport to an area that is covered by 4 top left tiles.
mMediator.scrollBy(10, 10); mScrollController.scrollBy(10, 10);
// Scroll should've triggered bitmap requests for an the 4th new tile as well as adjacent // Scroll should've triggered bitmap requests for an the 4th new tile as well as adjacent
// tiles. See comments on {@link #testBitmapRequest} for details on which tiles will be // tiles. See comments on {@link #testBitmapRequest} for details on which tiles will be
...@@ -568,7 +575,7 @@ public class PlayerFrameMediatorTest { ...@@ -568,7 +575,7 @@ public class PlayerFrameMediatorTest {
// Move the view port while staying within the 4 bitmap tiles in order to trigger the // Move the view port while staying within the 4 bitmap tiles in order to trigger the
// request logic again. Make sure only one new request is added, for the tile with a // request logic again. Make sure only one new request is added, for the tile with a
// compositing failure. // compositing failure.
mMediator.scrollBy(10, 10); mScrollController.scrollBy(10, 10);
Assert.assertEquals(9, mCompositorDelegate.mRequestedBitmap.size()); Assert.assertEquals(9, mCompositorDelegate.mRequestedBitmap.size());
Assert.assertEquals(new RequestedBitmap(mFrameGuid, getRectForTile(150, 200, 2, 0), 1f), Assert.assertEquals(new RequestedBitmap(mFrameGuid, getRectForTile(150, 200, 2, 0), 1f),
mCompositorDelegate.mRequestedBitmap.get( mCompositorDelegate.mRequestedBitmap.get(
...@@ -587,7 +594,7 @@ public class PlayerFrameMediatorTest { ...@@ -587,7 +594,7 @@ public class PlayerFrameMediatorTest {
// Scroll right and down by a within bounds amount. Both scroll directions should be // Scroll right and down by a within bounds amount. Both scroll directions should be
// effective. // effective.
Assert.assertTrue(mMediator.scrollBy(250f, 80f)); Assert.assertTrue(mScrollController.scrollBy(250f, 80f));
expectedViewPort.offset(250, 80); expectedViewPort.offset(250, 80);
Assert.assertEquals(expectedViewPort, mModel.get(PlayerFrameProperties.VIEWPORT)); Assert.assertEquals(expectedViewPort, mModel.get(PlayerFrameProperties.VIEWPORT));
} }
...@@ -633,7 +640,7 @@ public class PlayerFrameMediatorTest { ...@@ -633,7 +640,7 @@ public class PlayerFrameMediatorTest {
Assert.assertEquals(expectedVisibility, Assert.assertEquals(expectedVisibility,
getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS))); getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)));
mMediator.scrollBy(100, 0); mScrollController.scrollBy(100, 0);
expectedRects.set(0, new Rect(0, 0, 0, 0)); expectedRects.set(0, new Rect(0, 0, 0, 0));
expectedRects.set(1, new Rect(0, 0, 0, 0)); expectedRects.set(1, new Rect(0, 0, 0, 0));
expectedRects.set(2, new Rect(20, 35, 50, 65)); expectedRects.set(2, new Rect(20, 35, 50, 65));
...@@ -646,7 +653,7 @@ public class PlayerFrameMediatorTest { ...@@ -646,7 +653,7 @@ public class PlayerFrameMediatorTest {
Assert.assertEquals(expectedVisibility, Assert.assertEquals(expectedVisibility,
getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS))); getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)));
mMediator.scrollBy(-50, 0); mScrollController.scrollBy(-50, 0);
expectedRects.clear(); expectedRects.clear();
expectedRects.add(new Rect(-40, 20, 10, 120)); expectedRects.add(new Rect(-40, 20, 10, 120));
expectedRects.add(new Rect(-20, 130, 20, 160)); expectedRects.add(new Rect(-20, 130, 20, 160));
...@@ -660,7 +667,7 @@ public class PlayerFrameMediatorTest { ...@@ -660,7 +667,7 @@ public class PlayerFrameMediatorTest {
Assert.assertEquals(expectedVisibility, Assert.assertEquals(expectedVisibility,
getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS))); getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)));
mMediator.scrollBy(0, 200); mScrollController.scrollBy(0, 200);
expectedRects.clear(); expectedRects.clear();
expectedRects.add(new Rect(0, 0, 0, 0)); expectedRects.add(new Rect(0, 0, 0, 0));
expectedRects.add(new Rect(0, 0, 0, 0)); expectedRects.add(new Rect(0, 0, 0, 0));
...@@ -685,7 +692,7 @@ public class PlayerFrameMediatorTest { ...@@ -685,7 +692,7 @@ public class PlayerFrameMediatorTest {
mMediator.updateViewportSize(100, 200, 1f); mMediator.updateViewportSize(100, 200, 1f);
Rect expectedViewPort = new Rect(0, 0, 100, 200); Rect expectedViewPort = new Rect(0, 0, 100, 200);
mMediator.onFling(100, 0); mScrollController.onFling(100, 0);
expectedViewPort.offsetTo(mScroller.getFinalX(), mScroller.getFinalY()); expectedViewPort.offsetTo(mScroller.getFinalX(), mScroller.getFinalY());
ShadowLooper.runUiThreadTasks(); ShadowLooper.runUiThreadTasks();
Assert.assertTrue(mScroller.isFinished()); Assert.assertTrue(mScroller.isFinished());
...@@ -709,12 +716,12 @@ public class PlayerFrameMediatorTest { ...@@ -709,12 +716,12 @@ public class PlayerFrameMediatorTest {
// Scroll, and then click. The call to {@link PlayerFrameMediator} must account for the // Scroll, and then click. The call to {@link PlayerFrameMediator} must account for the
// scroll offset. // scroll offset.
mMediator.scrollBy(90, 100); mScrollController.scrollBy(90, 100);
mMediator.onTap(70, 50); mMediator.onTap(70, 50);
expectedClickedPoints.add(new ClickedPoint(mFrameGuid, 160, 150)); expectedClickedPoints.add(new ClickedPoint(mFrameGuid, 160, 150));
Assert.assertEquals(expectedClickedPoints, mCompositorDelegate.mClickedPoints); Assert.assertEquals(expectedClickedPoints, mCompositorDelegate.mClickedPoints);
mMediator.scrollBy(-40, -60); mScrollController.scrollBy(-40, -60);
mMediator.onTap(30, 80); mMediator.onTap(30, 80);
expectedClickedPoints.add(new ClickedPoint(mFrameGuid, 80, 120)); expectedClickedPoints.add(new ClickedPoint(mFrameGuid, 80, 120));
Assert.assertEquals(expectedClickedPoints, mCompositorDelegate.mClickedPoints); Assert.assertEquals(expectedClickedPoints, mCompositorDelegate.mClickedPoints);
...@@ -756,8 +763,8 @@ public class PlayerFrameMediatorTest { ...@@ -756,8 +763,8 @@ public class PlayerFrameMediatorTest {
// Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0. // Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0.
// The same bitmaps will be required but the grid will be double the size. // The same bitmaps will be required but the grid will be double the size.
Assert.assertTrue(mMediator.scaleBy(2f, 0, 0)); Assert.assertTrue(mScaleController.scaleBy(2f, 0, 0));
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
expectedRequiredBitmaps = new boolean[12][12]; expectedRequiredBitmaps = new boolean[12][12];
...@@ -768,8 +775,8 @@ public class PlayerFrameMediatorTest { ...@@ -768,8 +775,8 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest())); expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
// Reduce the scale factor by 0.5 returning to a scale of 1. // Reduce the scale factor by 0.5 returning to a scale of 1.
Assert.assertTrue(mMediator.scaleBy(0.5f, 0, 0)); Assert.assertTrue(mScaleController.scaleBy(0.5f, 0, 0));
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
expectedRequiredBitmaps = new boolean[6][6]; expectedRequiredBitmaps = new boolean[6][6];
...@@ -818,7 +825,7 @@ public class PlayerFrameMediatorTest { ...@@ -818,7 +825,7 @@ public class PlayerFrameMediatorTest {
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f));
// Both matricies should be identity to start. // Both matricies should be identity to start.
assertViewportStateIs(1f, 0f, 0f, mViewport); assertViewportStateIs(1f, 0f, 0f, mMediator.getViewport());
Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity()); Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity());
// Ensure the correct bitmaps are required and requested. // Ensure the correct bitmaps are required and requested.
Assert.assertTrue(Arrays.deepEquals( Assert.assertTrue(Arrays.deepEquals(
...@@ -826,7 +833,7 @@ public class PlayerFrameMediatorTest { ...@@ -826,7 +833,7 @@ public class PlayerFrameMediatorTest {
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
// STEP 2: Scroll slightly. // STEP 2: Scroll slightly.
mMediator.scrollBy(10, 15); mScrollController.scrollBy(10, 15);
// The current viewport covers portions of the 4 top left bitmap tiles. // The current viewport covers portions of the 4 top left bitmap tiles.
// ------------------------- // -------------------------
// | x | x | x | | | | // | x | x | x | | | |
...@@ -868,18 +875,18 @@ public class PlayerFrameMediatorTest { ...@@ -868,18 +875,18 @@ public class PlayerFrameMediatorTest {
expectedViewportMatrixValues[Matrix.MTRANS_Y] = 15; expectedViewportMatrixValues[Matrix.MTRANS_Y] = 15;
expectedViewportMatrix.setValues(expectedViewportMatrixValues); expectedViewportMatrix.setValues(expectedViewportMatrixValues);
assertViewportStateIs(expectedViewportMatrix, mViewport); assertViewportStateIs(expectedViewportMatrix, mMediator.getViewport());
Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity()); Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity());
// STEP 3: Now a scale factor of 2 will be applied. This will happen at a focal point of 50, // STEP 3: Now a scale factor of 2 will be applied. This will happen at a focal point of 50,
// 100. // 100.
Assert.assertTrue(mMediator.scaleBy(2f, 50f, 100f)); Assert.assertTrue(mScaleController.scaleBy(2f, 50f, 100f));
// Before the scaling commits both matricies should update. // Before the scaling commits both matricies should update.
expectedViewportMatrix.postScale(2f, 2f, -50f, -100f); expectedViewportMatrix.postScale(2f, 2f, -50f, -100f);
Matrix expectedBitmapMatrix = new Matrix(); Matrix expectedBitmapMatrix = new Matrix();
expectedBitmapMatrix.postScale(2f, 2f, 50f, 100f); expectedBitmapMatrix.postScale(2f, 2f, 50f, 100f);
assertViewportStateIs(expectedViewportMatrix, mViewport); assertViewportStateIs(expectedViewportMatrix, mMediator.getViewport());
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
// Bitmaps should be the same as before scaling until scaling is finished. // Bitmaps should be the same as before scaling until scaling is finished.
...@@ -887,7 +894,7 @@ public class PlayerFrameMediatorTest { ...@@ -887,7 +894,7 @@ public class PlayerFrameMediatorTest {
mCompositorDelegate.mRequestedBitmap.clear(); mCompositorDelegate.mRequestedBitmap.clear();
expectedRequestedBitmaps.clear(); expectedRequestedBitmaps.clear();
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
expectedRequiredBitmaps = new boolean[12][12]; expectedRequiredBitmaps = new boolean[12][12];
...@@ -926,12 +933,12 @@ public class PlayerFrameMediatorTest { ...@@ -926,12 +933,12 @@ public class PlayerFrameMediatorTest {
// STEP4: Now a scale factor of 0.5 will be applied. This will happen at a focal point of // STEP4: Now a scale factor of 0.5 will be applied. This will happen at a focal point of
// 50, 100. // 50, 100.
Assert.assertTrue(mMediator.scaleBy(0.5f, 50f, 100f)); Assert.assertTrue(mScaleController.scaleBy(0.5f, 50f, 100f));
// Ensure the matricies are correct mid-scale. // Ensure the matricies are correct mid-scale.
expectedViewportMatrix.postScale(0.5f, 0.5f, -50f, -100f); expectedViewportMatrix.postScale(0.5f, 0.5f, -50f, -100f);
expectedBitmapMatrix.postScale(0.5f, 0.5f, 50f, 100f); expectedBitmapMatrix.postScale(0.5f, 0.5f, 50f, 100f);
assertViewportStateIs(expectedViewportMatrix, mViewport); assertViewportStateIs(expectedViewportMatrix, mMediator.getViewport());
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
// Bitmaps should be the same as before scaling until scaling is finished. // Bitmaps should be the same as before scaling until scaling is finished.
...@@ -939,7 +946,7 @@ public class PlayerFrameMediatorTest { ...@@ -939,7 +946,7 @@ public class PlayerFrameMediatorTest {
mCompositorDelegate.mRequestedBitmap.clear(); mCompositorDelegate.mRequestedBitmap.clear();
expectedRequestedBitmaps.clear(); expectedRequestedBitmaps.clear();
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
expectedRequiredBitmaps = new boolean[6][6]; expectedRequiredBitmaps = new boolean[6][6];
...@@ -989,18 +996,18 @@ public class PlayerFrameMediatorTest { ...@@ -989,18 +996,18 @@ public class PlayerFrameMediatorTest {
// | | | | | | | // | | | | | | |
// ------------------------- // -------------------------
// | | | | | | | // | | | | | | |
Assert.assertTrue(mMediator.scaleBy(2f, 100f, 200f)); Assert.assertTrue(mScaleController.scaleBy(2f, 100f, 200f));
expectedViewportMatrix.postScale(2f, 2f, -100f, -200f); expectedViewportMatrix.postScale(2f, 2f, -100f, -200f);
expectedBitmapMatrix.postScale(2f, 2f, 100f, 200f); expectedBitmapMatrix.postScale(2f, 2f, 100f, 200f);
assertViewportStateIs(expectedViewportMatrix, mViewport); assertViewportStateIs(expectedViewportMatrix, mMediator.getViewport());
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
mCompositorDelegate.mRequestedBitmap.clear(); mCompositorDelegate.mRequestedBitmap.clear();
expectedRequestedBitmaps.clear(); expectedRequestedBitmaps.clear();
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
expectedRequiredBitmaps = new boolean[12][12]; expectedRequiredBitmaps = new boolean[12][12];
...@@ -1090,7 +1097,7 @@ public class PlayerFrameMediatorTest { ...@@ -1090,7 +1097,7 @@ public class PlayerFrameMediatorTest {
expectedVisibility.set(1, false); expectedVisibility.set(1, false);
// During scaling the second subframe should disappear from the viewport. // During scaling the second subframe should disappear from the viewport.
Assert.assertTrue(mMediator.scaleBy(2f, 0f, 0f)); Assert.assertTrue(mScaleController.scaleBy(2f, 0f, 0f));
Assert.assertEquals(expectedViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)); Assert.assertEquals(expectedViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
Assert.assertEquals(expectedRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS)); Assert.assertEquals(expectedRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
Assert.assertEquals(expectedVisibility, Assert.assertEquals(expectedVisibility,
...@@ -1100,7 +1107,7 @@ public class PlayerFrameMediatorTest { ...@@ -1100,7 +1107,7 @@ public class PlayerFrameMediatorTest {
inOrderMediator1.verify(subFrame1Mediator) inOrderMediator1.verify(subFrame1Mediator)
.setBitmapScaleMatrixOfSubframe(argThat(new MatrixMatcher(expectedMatrix)), eq(2f)); .setBitmapScaleMatrixOfSubframe(argThat(new MatrixMatcher(expectedMatrix)), eq(2f));
Assert.assertTrue(mMediator.scaleFinished(1f, 0f, 0f)); Assert.assertTrue(mScaleController.scaleFinished(1f, 0f, 0f));
mBitmapStateController.swapForTest(); mBitmapStateController.swapForTest();
inOrderMediator1.verify(subFrame1Mediator).resetScaleFactor(); inOrderMediator1.verify(subFrame1Mediator).resetScaleFactor();
inOrderMediator1.verify(subFrame1Mediator).forceRedraw(); inOrderMediator1.verify(subFrame1Mediator).forceRedraw();
...@@ -1113,7 +1120,7 @@ public class PlayerFrameMediatorTest { ...@@ -1113,7 +1120,7 @@ public class PlayerFrameMediatorTest {
.setBitmapScaleMatrixOfSubframe(argThat(new MatrixMatcher(expectedMatrix)), eq(1f)); .setBitmapScaleMatrixOfSubframe(argThat(new MatrixMatcher(expectedMatrix)), eq(1f));
// Scroll so the second subframe is back in the viewport.. // Scroll so the second subframe is back in the viewport..
mMediator.scrollBy(20, 40); mScrollController.scrollBy(20, 40);
expectedRects.clear(); expectedRects.clear();
expectedRects.add(new Rect(0, 0, 100, 40)); expectedRects.add(new Rect(0, 0, 100, 40));
expectedRects.add(new Rect(40, 60, 120, 280)); expectedRects.add(new Rect(40, 60, 120, 280));
...@@ -1126,7 +1133,7 @@ public class PlayerFrameMediatorTest { ...@@ -1126,7 +1133,7 @@ public class PlayerFrameMediatorTest {
getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS))); getVisibilities(mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)));
// Scale out keeping the subframes in the viewport.. // Scale out keeping the subframes in the viewport..
Assert.assertTrue(mMediator.scaleBy(0.75f, 25f, 50f)); Assert.assertTrue(mScaleController.scaleBy(0.75f, 25f, 50f));
expectedRects.clear(); expectedRects.clear();
expectedRects.add(new Rect(6, 12, 81, 42)); expectedRects.add(new Rect(6, 12, 81, 42));
expectedRects.add(new Rect(36, 57, 96, 222)); expectedRects.add(new Rect(36, 57, 96, 222));
...@@ -1210,15 +1217,32 @@ public class PlayerFrameMediatorTest { ...@@ -1210,15 +1217,32 @@ public class PlayerFrameMediatorTest {
Assert.assertFalse( Assert.assertFalse(
"User interaction callback shouldn't have been called", mHasUserInteraction); "User interaction callback shouldn't have been called", mHasUserInteraction);
mMediator.scrollBy(0, 10); mScrollController.scrollBy(0, 10);
Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction); Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction);
mHasUserInteraction = false; mHasUserInteraction = false;
mMediator.onFling(0, 10); mScrollController.onFling(0, 10);
Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction); Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction);
mHasUserInteraction = false; mHasUserInteraction = false;
mMediator.scaleBy(1.5f, 20, 30); mScaleController.scaleBy(1.5f, 20, 30);
Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction); Assert.assertTrue("User interaction callback should have been called", mHasUserInteraction);
} }
/**
* Tests that bitmap matrix is offset correctly.
*/
@Test
public void testOffsetBitmapScaleMatrix() {
Matrix bitmapScaleMatrix = mModel.get(PlayerFrameProperties.SCALE_MATRIX);
Matrix expectedBitmapScaleMatrix = new Matrix();
mMediator.offsetBitmapScaleMatrix(5f, 10f); // Should no-op.
Assert.assertEquals(expectedBitmapScaleMatrix, bitmapScaleMatrix);
bitmapScaleMatrix.postScale(2f, 2f);
mMediator.offsetBitmapScaleMatrix(5f, 10f);
expectedBitmapScaleMatrix.postScale(2f, 2f);
expectedBitmapScaleMatrix.postTranslate(-5f, -10f);
Assert.assertEquals(expectedBitmapScaleMatrix, bitmapScaleMatrix);
}
} }
...@@ -7,6 +7,7 @@ package org.chromium.components.paintpreview.player.frame; ...@@ -7,6 +7,7 @@ package org.chromium.components.paintpreview.player.frame;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.when;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.util.Size; import android.util.Size;
...@@ -59,29 +60,16 @@ public class PlayerFrameScaleControllerTest { ...@@ -59,29 +60,16 @@ public class PlayerFrameScaleControllerTest {
Callback<Boolean> mScaleListener = (Boolean didFinish) -> mDidScale = true; Callback<Boolean> mScaleListener = (Boolean didFinish) -> mDidScale = true;
mViewport = new PlayerFrameViewport(); mViewport = new PlayerFrameViewport();
mBitmapScaleMatrix = new Matrix(); mBitmapScaleMatrix = new Matrix();
mScaleController = Size contentSize = new Size(CONTENT_WIDTH, CONTENT_HEIGHT);
new PlayerFrameScaleController(mViewport, new Size(CONTENT_WIDTH, CONTENT_HEIGHT), when(mMediatorDelegateMock.getViewport()).thenReturn(mViewport);
mBitmapScaleMatrix, mMediatorDelegateMock, mScaleListener); when(mMediatorDelegateMock.getContentSize()).thenReturn(contentSize);
mScaleController.calculateInitialScaleFactor(CONTENT_WIDTH); when(mMediatorDelegateMock.getInitialScaleFactor()).thenReturn(1f);
mViewport.setScale(mScaleController.getInitialScaleFactor()); mScaleController = new PlayerFrameScaleController(
mBitmapScaleMatrix, mMediatorDelegateMock, mScaleListener);
mViewport.setScale(1f);
mViewport.setSize(100, 100); mViewport.setSize(100, 100);
} }
/**
* Tests calculating and getting the initial scale factor.
*/
@Test
public void testInitialScaleFactor() {
mScaleController.calculateInitialScaleFactor(CONTENT_WIDTH);
Assert.assertEquals(1f, mScaleController.getInitialScaleFactor(), TOLERANCE);
mScaleController.calculateInitialScaleFactor(250);
Assert.assertEquals(0.5f, mScaleController.getInitialScaleFactor(), TOLERANCE);
mScaleController.calculateInitialScaleFactor(1000);
Assert.assertEquals(2f, mScaleController.getInitialScaleFactor(), TOLERANCE);
}
/** /**
* Tests the limits of scaling. * Tests the limits of scaling.
*/ */
......
...@@ -56,9 +56,11 @@ public class PlayerFrameScrollControllerTest { ...@@ -56,9 +56,11 @@ public class PlayerFrameScrollControllerTest {
Runnable mOnScrollListener = () -> mDidScroll = true; Runnable mOnScrollListener = () -> mDidScroll = true;
Runnable mOnFlingListener = () -> mDidFling = true; Runnable mOnFlingListener = () -> mDidFling = true;
mViewport = new PlayerFrameViewport(); mViewport = new PlayerFrameViewport();
mScrollController = new PlayerFrameScrollController(mScroller, mViewport, when(mMediatorDelegateMock.getViewport()).thenReturn(mViewport);
new Size(CONTENT_WIDTH, CONTENT_HEIGHT), mMediatorDelegateMock, mOnScrollListener, when(mMediatorDelegateMock.getContentSize())
mOnFlingListener); .thenReturn(new Size(CONTENT_WIDTH, CONTENT_HEIGHT));
mScrollController = new PlayerFrameScrollController(
mScroller, mMediatorDelegateMock, mOnScrollListener, mOnFlingListener);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment