Commit 8a8a5f27 authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] Multi-frame Player Test

This CL adds a framework and a basic test for displaying multiple-
frames for the Player Test. This allows us to exercise and test much
more of the functionality of the player and help avoid regressions.

Follow-up CLs will add a test for
- Scrolling subframes
- Scaling with subframes
- Link clicks of subframes
- And possibly render tests

Bug: 1106035
Change-Id: Iada1df0ce929bde2b38907a38725efd1edcd5a96
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2316407Reviewed-by: default avatarMehran Mahmoudi <mahmoudi@chromium.org>
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792285}
parent 0161853a
......@@ -91,6 +91,7 @@ android_library("player_java_test_support") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
sources = [
"javatests/src/org/chromium/components/paintpreview/player/FrameData.java",
"javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestRule.java",
"javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestService.java",
]
......
......@@ -190,4 +190,9 @@ public class PlayerManager {
public View getView() {
return mHostView;
}
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
return mRootFrameCoordinator.checkRequiredBitmapsLoadedForTest();
}
}
......@@ -289,4 +289,18 @@ public class PlayerFrameBitmapState {
mPendingBitmapRequests[mRequestRow][mRequestCol] = false;
}
}
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
if (mBitmapMatrix == null || mRequiredBitmaps == null) return false;
for (int row = 0; row < mBitmapMatrix.length; row++) {
for (int col = 0; col < mBitmapMatrix[0].length; col++) {
if (mRequiredBitmaps[row][col] && mBitmapMatrix[row][col] == null) {
return false;
}
}
}
return true;
}
}
......@@ -12,6 +12,7 @@ import android.view.ViewConfiguration;
import android.widget.OverScroller;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.UnguessableToken;
import org.chromium.components.paintpreview.player.OverscrollHandler;
......@@ -83,4 +84,9 @@ public class PlayerFrameCoordinator {
public View getView() {
return mView;
}
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
return mMediator.checkRequiredBitmapsLoadedForTest();
}
}
......@@ -345,4 +345,19 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
private void adjustInitialScaleFactor(float width) {
mInitialScaleFactor = width / ((float) mContentSize.getWidth());
}
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
PlayerFrameBitmapState state = mBitmapStateController.getBitmapState(false);
assert mBitmapStateController.isVisible(state);
boolean hasBitmaps = state.checkRequiredBitmapsLoadedForTest();
if (!hasBitmaps) return false;
for (int i = 0; i < mSubFrameViews.size(); i++) {
if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue;
hasBitmaps &= mSubFrameMediators.get(i).checkRequiredBitmapsLoadedForTest();
}
return hasBitmaps;
}
}
......@@ -5,9 +5,13 @@
#ifndef COMPONENTS_PAINT_PREVIEW_PLAYER_ANDROID_JAVATESTS_PAINT_PREVIEW_TEST_SERVICE_H_
#define COMPONENTS_PAINT_PREVIEW_PLAYER_ANDROID_JAVATESTS_PAINT_PREVIEW_TEST_SERVICE_H_
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "components/paint_preview/common/serial_utils.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace paint_preview {
......@@ -20,17 +24,37 @@ class PaintPreviewTestService : public PaintPreviewBaseService {
PaintPreviewTestService(const PaintPreviewTestService&) = delete;
PaintPreviewTestService& operator=(const PaintPreviewTestService&) = delete;
jboolean CreateSingleSkpForKey(
base::android::ScopedJavaLocalRef<jintArray> CreateSingleSkp(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_key,
const base::android::JavaParamRef<jstring>& j_url,
jint j_id,
jint j_width,
jint j_height,
const base::android::JavaParamRef<jintArray>& j_link_rects,
const base::android::JavaParamRef<jobjectArray>& j_link_urls);
const base::android::JavaParamRef<jobjectArray>& j_link_urls,
const base::android::JavaParamRef<jintArray>& j_child_rects);
jboolean SerializeFrames(JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_key,
const base::android::JavaParamRef<jstring>& j_url);
private:
struct Frame {
explicit Frame(const base::UnguessableToken& token);
~Frame();
Frame(const Frame& rhs) = delete;
Frame& operator=(const Frame& rhs) = delete;
Frame(Frame&& rhs) noexcept;
Frame& operator=(Frame&& rhs) noexcept;
base::UnguessableToken guid;
sk_sp<SkPicture> skp;
PaintPreviewFrameProto proto;
PictureSerializationContext ctx;
};
base::FilePath test_data_dir_;
base::flat_map<uint32_t, Frame> frames_;
};
} // namespace paint_preview
......
// 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;
import android.graphics.Rect;
import android.util.Size;
/**
* Stores data about a frame for testing.
*/
public class FrameData {
private final Size mSize;
private final int[] mLinkRects;
private final String[] mLinks;
private final int[] mChildRects;
private final FrameData[] mChildFrames;
public FrameData(Size size, Rect[] linkRects, String[] links, Rect[] childRects,
FrameData[] childFrames) {
mSize = size;
assert linkRects.length == links.length;
mLinkRects = flattenRects(linkRects);
mLinks = links;
assert childRects.length == childFrames.length;
mChildRects = flattenRects(childRects);
mChildFrames = childFrames;
}
public int getWidth() {
return mSize.getWidth();
}
public int getHeight() {
return mSize.getHeight();
}
public int[] getFlattenedLinkRects() {
return mLinkRects;
}
public String[] getLinks() {
return mLinks;
}
public int[] getFlattenedChildRects() {
return mChildRects;
}
public FrameData[] getChildFrames() {
return mChildFrames;
}
private int[] flattenRects(Rect[] rects) {
int flattenedRects[] = new int[rects.length * 4];
for (int i = 0; i < rects.length; i++) {
flattenedRects[i * 4] = rects[i].left;
flattenedRects[i * 4 + 1] = rects[i].top;
flattenedRects[i * 4 + 2] = rects[i].width();
flattenedRects[i * 4 + 3] = rects[i].height();
}
return flattenedRects;
}
}
......@@ -9,6 +9,7 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.util.Size;
import android.view.View;
import android.view.ViewGroup;
......@@ -85,13 +86,8 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
destroyed.waitForFirst();
}
/**
* Tests the the player correctly initializes and displays a sample paint preview with 1 frame.
*/
@Test
@MediumTest
public void singleFrameDisplayTest() {
initPlayerManager();
private void displayTest(boolean multipleFrames) {
initPlayerManager(multipleFrames);
final View playerHostView = mPlayerManager.getView();
final View activityContentView = getActivity().findViewById(android.R.id.content);
......@@ -106,13 +102,32 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
}, TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
}
/**
* Tests the the player correctly initializes and displays a sample paint preview with 1 frame.
*/
@Test
@MediumTest
public void singleFrameDisplayTest() {
displayTest(false);
}
/**
* Tests the player correctly initializes and displays a sample paint preview with multiple
* frames.
*/
@Test
@MediumTest
public void multiFrameDisplayTest() {
displayTest(true);
}
/**
* Tests that link clicks in the player work correctly.
*/
@Test
@MediumTest
public void linkClickTest() {
initPlayerManager();
initPlayerManager(true);
final View playerHostView = mPlayerManager.getView();
// Click on a link that is visible in the default viewport.
......@@ -131,7 +146,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
@MediumTest
@DisabledTest(message = "https://crbug.com/1093083")
public void overscrollRefreshTest() throws Exception {
initPlayerManager();
initPlayerManager(true);
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
int deviceHeight = uiDevice.getDisplayHeight();
int statusBarHeight = statusBarHeight();
......@@ -174,7 +189,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
@Test
@MediumTest
public void scaleSmokeTest() throws Exception {
initPlayerManager();
initPlayerManager(true);
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// Query all FrameLayout objects as the PlayerFrameView isn't recognized.
......@@ -239,7 +254,47 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
uiDevice.swipe(50, fromY, 50, toY, swipeSteps);
}
private void initPlayerManager() {
private void initSingleSkp(PaintPreviewTestService service) {
FrameData singleFrame = new FrameData(new Size(TEST_PAGE_WIDTH, TEST_PAGE_HEIGHT),
new Rect[] {mInViewportLinkRect, mOutOfViewportLinkRect},
new String[] {TEST_IN_VIEWPORT_LINK_URL, TEST_OUT_OF_VIEWPORT_LINK_URL},
new Rect[] {}, new FrameData[] {});
Assert.assertTrue(service.createFramesForKey(TEST_DIRECTORY_KEY, TEST_URL, singleFrame));
}
private void initMultiSkp(PaintPreviewTestService service) {
// This creates a frame tree of the form
//
// Main
// / \
// A B
// | |
// C D
//
// A: Doesn't scroll contains a nested c
// B: Scrolls contains a nested d out of frame
// C: Doesn't scroll
// D: Scrolls
FrameData childD = new FrameData(new Size(300, 500), new Rect[] {}, new String[] {},
new Rect[] {}, new FrameData[] {});
FrameData childB = new FrameData(new Size(900, 3000), new Rect[] {}, new String[] {},
new Rect[] {new Rect(50, 2000, 150, 2100)}, new FrameData[] {childD});
FrameData childC = new FrameData(new Size(400, 200), new Rect[] {}, new String[] {},
new Rect[] {}, new FrameData[] {});
FrameData childA = new FrameData(new Size(500, 300), new Rect[] {}, new String[] {},
new Rect[] {new Rect(50, 50, 450, 250)}, new FrameData[] {childC});
FrameData rootFrame = new FrameData(new Size(TEST_PAGE_WIDTH, TEST_PAGE_HEIGHT),
new Rect[] {mInViewportLinkRect, mOutOfViewportLinkRect},
new String[] {TEST_IN_VIEWPORT_LINK_URL, TEST_OUT_OF_VIEWPORT_LINK_URL},
new Rect[] {new Rect(100, 100, 600, 400), new Rect(50, 1000, 700, 2000)},
new FrameData[] {childA, childB});
Assert.assertTrue(service.createFramesForKey(TEST_DIRECTORY_KEY, TEST_URL, rootFrame));
}
private void initPlayerManager(boolean multiSkp) {
mLinkClickHandler = new TestLinkClickHandler();
mRefreshedCallback = new CallbackHelper();
CallbackHelper viewReady = new CallbackHelper();
......@@ -248,17 +303,16 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
PaintPreviewTestService service =
new PaintPreviewTestService(mTempFolder.getRoot().getPath());
Assert.assertTrue(service.createSingleSkpForKey(TEST_DIRECTORY_KEY, TEST_URL,
TEST_PAGE_WIDTH, TEST_PAGE_HEIGHT,
new Rect[] {mInViewportLinkRect, mOutOfViewportLinkRect},
new String[] {TEST_IN_VIEWPORT_LINK_URL, TEST_OUT_OF_VIEWPORT_LINK_URL}));
if (multiSkp) {
initMultiSkp(service);
} else {
initSingleSkp(service);
}
mPlayerManager = new PlayerManager(new GURL(TEST_URL), getActivity(), service,
TEST_DIRECTORY_KEY, mLinkClickHandler,
()
-> { mRefreshedCallback.notifyCalled(); },
()
-> { viewReady.notifyCalled(); },
null, 0xffffffff, () -> { mInitializationFailed = true; }, false);
TEST_DIRECTORY_KEY, mLinkClickHandler, mRefreshedCallback::notifyCalled,
viewReady::notifyCalled, null, 0xffffffff,
() -> { mInitializationFailed = true; }, false);
mPlayerManager.setCompressOnClose(false);
getActivity().setContentView(mPlayerManager.getView());
});
......@@ -285,6 +339,14 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
((ViewGroup) mPlayerManager.getView()).getChildCount(),
Matchers.greaterThan(0));
}, TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
CriteriaHelper.pollUiThread(() -> {
Criteria.checkThat("Required bitmaps were not loaded.",
mPlayerManager.checkRequiredBitmapsLoadedForTest(), Matchers.is(true));
}, TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
if (mInitializationFailed) {
Assert.fail("Compositor may have crashed.");
}
}
/*
......
......@@ -4,8 +4,6 @@
package org.chromium.components.paintpreview.player;
import android.graphics.Rect;
import org.chromium.base.Log;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
......@@ -28,35 +26,41 @@ public class PaintPreviewTestService implements NativePaintPreviewServiceProvide
return mNativePaintPreviewTestService;
}
public boolean createSingleSkpForKey(
String key, String url, int width, int height, Rect[] linkRects, String[] links) {
public boolean createFramesForKey(String key, String url, FrameData rootFrameData) {
if (mNativePaintPreviewTestService == 0) {
Log.e(TAG, "No native service.");
return false;
}
assert linkRects.length == links.length;
createFrames(rootFrameData, 0);
int flattenedRects[] = new int[linkRects.length * 4];
for (int i = 0; i < linkRects.length; i++) {
flattenedRects[i * 4] = linkRects[i].left;
flattenedRects[i * 4 + 1] = linkRects[i].top;
flattenedRects[i * 4 + 2] = linkRects[i].width();
flattenedRects[i * 4 + 3] = linkRects[i].height();
}
boolean ret = PaintPreviewTestServiceJni.get().serializeFrames(
mNativePaintPreviewTestService, key, url);
boolean ret = PaintPreviewTestServiceJni.get().createSingleSkpForKey(
mNativePaintPreviewTestService, key, url, width, height, flattenedRects, links);
if (!ret) {
Log.e(TAG, "Native failed to setup files for testing.");
}
return ret;
}
private void createFrames(FrameData frameData, int id) {
int[] childIds = PaintPreviewTestServiceJni.get().createSingleSkp(
mNativePaintPreviewTestService, id, frameData.getWidth(), frameData.getHeight(),
frameData.getFlattenedLinkRects(), frameData.getLinks(),
frameData.getFlattenedChildRects());
FrameData[] childFrames = frameData.getChildFrames();
assert childIds.length == childFrames.length;
for (int i = 0; i < childIds.length; i++) {
createFrames(childFrames[i], childIds[i]);
}
}
@NativeMethods
interface Natives {
long getInstance(String path);
boolean createSingleSkpForKey(long nativePaintPreviewTestService, String key, String url,
int width, int height, int[] flattenedRects, String[] links);
int[] createSingleSkp(long nativePaintPreviewTestService, int id, int width, int height,
int[] flattenedLinkRects, String[] links, int[] flattenedChildRects);
boolean serializeFrames(long nativePaintPreviewTestService, String key, String url);
}
}
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