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") { ...@@ -91,6 +91,7 @@ android_library("player_java_test_support") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
sources = [ 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/PaintPreviewTestRule.java",
"javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestService.java", "javatests/src/org/chromium/components/paintpreview/player/PaintPreviewTestService.java",
] ]
......
...@@ -190,4 +190,9 @@ public class PlayerManager { ...@@ -190,4 +190,9 @@ public class PlayerManager {
public View getView() { public View getView() {
return mHostView; return mHostView;
} }
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
return mRootFrameCoordinator.checkRequiredBitmapsLoadedForTest();
}
} }
...@@ -289,4 +289,18 @@ public class PlayerFrameBitmapState { ...@@ -289,4 +289,18 @@ public class PlayerFrameBitmapState {
mPendingBitmapRequests[mRequestRow][mRequestCol] = false; 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; ...@@ -12,6 +12,7 @@ import android.view.ViewConfiguration;
import android.widget.OverScroller; import android.widget.OverScroller;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
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.OverscrollHandler;
...@@ -83,4 +84,9 @@ public class PlayerFrameCoordinator { ...@@ -83,4 +84,9 @@ public class PlayerFrameCoordinator {
public View getView() { public View getView() {
return mView; return mView;
} }
@VisibleForTesting
public boolean checkRequiredBitmapsLoadedForTest() {
return mMediator.checkRequiredBitmapsLoadedForTest();
}
} }
...@@ -345,4 +345,19 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato ...@@ -345,4 +345,19 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate, PlayerFrameMediato
private void adjustInitialScaleFactor(float width) { private void adjustInitialScaleFactor(float width) {
mInitialScaleFactor = width / ((float) mContentSize.getWidth()); 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;
}
} }
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/strings/strcat.h"
#include "components/paint_preview/browser/paint_preview_base_service.h" #include "components/paint_preview/browser/paint_preview_base_service.h"
#include "components/paint_preview/browser/test_paint_preview_policy.h" #include "components/paint_preview/browser/test_paint_preview_policy.h"
#include "components/paint_preview/common/file_stream.h" #include "components/paint_preview/common/file_stream.h"
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include "components/paint_preview/player/android/javatests_jni_headers/PaintPreviewTestService_jni.h" #include "components/paint_preview/player/android/javatests_jni_headers/PaintPreviewTestService_jni.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRect.h"
...@@ -31,6 +33,68 @@ namespace paint_preview { ...@@ -31,6 +33,68 @@ namespace paint_preview {
const char kPaintPreviewDir[] = "paint_preview"; const char kPaintPreviewDir[] = "paint_preview";
const char kTestDirName[] = "PaintPreviewTestService"; const char kTestDirName[] = "PaintPreviewTestService";
constexpr int kSquareSideLen = 50;
namespace {
void CreateBackground(SkCanvas* canvas,
const SkColor& color,
uint32_t width,
uint32_t height) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas->drawRect(SkRect::MakeWH(width, height), paint);
paint.setColor(color);
for (uint32_t j = 0; j * kSquareSideLen < height; ++j) {
for (uint32_t i = (j % 2); i * kSquareSideLen < width; i += 2) {
canvas->drawRect(SkRect::MakeXYWH(i * kSquareSideLen, j * kSquareSideLen,
kSquareSideLen, kSquareSideLen),
paint);
}
}
}
void AddLinks(SkCanvas* canvas,
PaintPreviewFrameProto& frame,
const std::vector<std::string> link_urls,
const std::vector<int> link_rects) {
SkPaint paint;
paint.setColor(SK_ColorCYAN);
for (size_t i = 0; i < link_urls.size(); ++i) {
auto* link_proto = frame.add_links();
link_proto->set_url(link_urls[i]);
auto* rect = link_proto->mutable_rect();
int x = link_rects[i * 4];
int y = link_rects[i * 4 + 1];
int width = link_rects[i * 4 + 2];
int height = link_rects[i * 4 + 3];
rect->set_x(x);
rect->set_y(y);
rect->set_width(width);
rect->set_height(height);
canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint);
}
}
bool WriteSkp(sk_sp<SkPicture> skp,
const base::FilePath& skp_path,
PictureSerializationContext* pctx) {
FileWStream wstream(base::File(
skp_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
TypefaceUsageMap typeface_map;
TypefaceSerializationContext tctx(&typeface_map);
auto procs = MakeSerialProcs(pctx, &tctx);
skp->serialize(&wstream, &procs);
wstream.Close();
if (wstream.DidWriteFail()) {
LOG(ERROR) << "SKP Write failed";
return false;
}
LOG(INFO) << "Wrote SKP " << wstream.ActualBytesWritten() << " bytes";
return true;
}
} // namespace
jlong JNI_PaintPreviewTestService_GetInstance( jlong JNI_PaintPreviewTestService_GetInstance(
JNIEnv* env, JNIEnv* env,
...@@ -50,14 +114,101 @@ PaintPreviewTestService::PaintPreviewTestService(const base::FilePath& path) ...@@ -50,14 +114,101 @@ PaintPreviewTestService::PaintPreviewTestService(const base::FilePath& path)
PaintPreviewTestService::~PaintPreviewTestService() = default; PaintPreviewTestService::~PaintPreviewTestService() = default;
jboolean PaintPreviewTestService::CreateSingleSkpForKey( base::android::ScopedJavaLocalRef<jintArray>
PaintPreviewTestService::CreateSingleSkp(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jstring>& j_key, jint j_id,
const JavaParamRef<jstring>& j_url,
jint j_width, jint j_width,
jint j_height, jint j_height,
const JavaParamRef<jintArray>& j_link_rects, const JavaParamRef<jintArray>& j_link_rects,
const JavaParamRef<jobjectArray>& j_link_urls) { const JavaParamRef<jobjectArray>& j_link_urls,
const JavaParamRef<jintArray>& j_child_rects) {
const int id = static_cast<int>(j_id);
uint32_t width = static_cast<uint32_t>(j_width);
uint32_t height = static_cast<uint32_t>(j_height);
if (id == 0)
frames_.emplace(0, Frame(base::UnguessableToken::Create()));
std::vector<int> out;
auto it = frames_.find(id);
if (it == frames_.end()) {
LOG(ERROR) << "Unexpected frame ID.";
return base::android::ToJavaIntArray(env, out);
}
auto* data = &it->second;
SkPictureRecorder recorder;
auto* canvas = recorder.beginRecording(SkRect::MakeWH(width, height));
SkColor color;
if (id == 0) {
color = SK_ColorGRAY;
} else {
constexpr SkColor colors[4] = {SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN,
SK_ColorMAGENTA};
color = colors[id % 4];
}
CreateBackground(canvas, color, width, height);
{
// Scope the reference to |frame| here to prevent using when |data| may be
// invalidated downstream.
PaintPreviewFrameProto& frame = data->proto;
frame.set_embedding_token_low(data->guid.GetLowForSerialization());
frame.set_embedding_token_high(data->guid.GetHighForSerialization());
frame.set_is_main_frame(id == 0);
// No initial offset.
frame.set_scroll_offset_x(0);
frame.set_scroll_offset_y(0);
std::vector<std::string> link_urls;
base::android::AppendJavaStringArrayToStringVector(env, j_link_urls,
&link_urls);
std::vector<int> link_rects;
base::android::JavaIntArrayToIntVector(env, j_link_rects, &link_rects);
AddLinks(canvas, frame, link_urls, link_rects);
}
std::vector<int> child_rects;
base::android::JavaIntArrayToIntVector(env, j_child_rects, &child_rects);
// Add sub pictures.
for (size_t i = 0; i < child_rects.size() / 4; ++i) {
const int x = child_rects[i * 4];
const int y = child_rects[i * 4 + 1];
const int width = child_rects[i * 4 + 2];
const int height = child_rects[i * 4 + 3];
auto sub_pic =
SkPicture::MakePlaceholder(SkRect::MakeXYWH(x, y, width, height));
SkMatrix matrix = SkMatrix::Translate(x, y);
uint32_t sub_id = sub_pic->uniqueID();
canvas->drawPicture(sub_pic, &matrix, nullptr);
out.push_back(sub_id);
auto token = base::UnguessableToken::Create();
{
auto* id_map_entry = data->proto.add_content_id_to_embedding_tokens();
id_map_entry->set_embedding_token_low(token.GetLowForSerialization());
id_map_entry->set_embedding_token_high(token.GetHighForSerialization());
id_map_entry->set_content_id(sub_id);
}
frames_.emplace(sub_id, Frame(token));
// Re-find |data| as it may have moved when emplacing the new frame.
it = frames_.find(id);
data = &it->second;
data->ctx.insert(std::make_pair(sub_id, token));
}
data->skp = recorder.finishRecordingAsPicture();
return base::android::ToJavaIntArray(env, out);
}
jboolean PaintPreviewTestService::SerializeFrames(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_key,
const base::android::JavaParamRef<jstring>& j_url) {
base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedAllowBlockingForTesting allow_blocking;
if (!base::PathExists(test_data_dir_)) { if (!base::PathExists(test_data_dir_)) {
base::File::Error error; base::File::Error error;
...@@ -67,7 +218,6 @@ jboolean PaintPreviewTestService::CreateSingleSkpForKey( ...@@ -67,7 +218,6 @@ jboolean PaintPreviewTestService::CreateSingleSkpForKey(
return false; return false;
} }
} }
base::FilePath path = test_data_dir_.AppendASCII( base::FilePath path = test_data_dir_.AppendASCII(
base::android::ConvertJavaStringToUTF8(env, j_key)); base::android::ConvertJavaStringToUTF8(env, j_key));
if (!base::CreateDirectory(path)) { if (!base::CreateDirectory(path)) {
...@@ -75,68 +225,49 @@ jboolean PaintPreviewTestService::CreateSingleSkpForKey( ...@@ -75,68 +225,49 @@ jboolean PaintPreviewTestService::CreateSingleSkpForKey(
return false; return false;
} }
uint32_t width = static_cast<uint32_t>(j_width); auto root_it = frames_.find(0);
uint32_t height = static_cast<uint32_t>(j_height); if (root_it == frames_.end()) {
LOG(ERROR) << "No root frame";
SkPictureRecorder recorder;
auto* canvas = recorder.beginRecording(SkRect::MakeWH(width, height));
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas->drawRect(SkRect::MakeWH(width, height), paint);
paint.setColor(SK_ColorGRAY);
const int kSquareSideLen = 50;
for (uint32_t j = 0; j * kSquareSideLen < height; ++j) {
for (uint32_t i = (j % 2); i * kSquareSideLen < width; i += 2) {
canvas->drawRect(SkRect::MakeXYWH(i * kSquareSideLen, j * kSquareSideLen,
kSquareSideLen, kSquareSideLen),
paint);
}
}
auto skp = recorder.finishRecordingAsPicture();
auto skp_path = path.AppendASCII("test_file.skp");
FileWStream wstream(base::File(
skp_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
skp->serialize(&wstream);
wstream.Close();
if (wstream.DidWriteFail()) {
LOG(ERROR) << "SKP Write failed";
return false; return false;
} }
LOG(INFO) << "Wrote SKP " << wstream.ActualBytesWritten() << " bytes";
PaintPreviewProto paint_preview; PaintPreviewProto paint_preview;
auto* metadata = paint_preview.mutable_metadata(); auto* metadata = paint_preview.mutable_metadata();
metadata->set_url(base::android::ConvertJavaStringToUTF8(env, j_url)); metadata->set_url(base::android::ConvertJavaStringToUTF8(env, j_url));
auto* root_frame = paint_preview.mutable_root_frame(); auto skp_path =
auto token = base::UnguessableToken::Create(); path.AppendASCII(base::StrCat({root_it->second.guid.ToString(), ".skp"}));
root_frame->set_file_path(skp_path.AsUTF8Unsafe()); root_it->second.proto.set_file_path(skp_path.AsUTF8Unsafe());
root_frame->set_embedding_token_low(token.GetLowForSerialization()); *paint_preview.mutable_root_frame() = root_it->second.proto;
root_frame->set_embedding_token_high(token.GetHighForSerialization()); if (!WriteSkp(root_it->second.skp, skp_path, &(root_it->second.ctx)))
root_frame->set_is_main_frame(true); return false;
// No initial offset.
root_frame->set_scroll_offset_x(0); for (auto it = frames_.begin(); it != frames_.end(); ++it) {
root_frame->set_scroll_offset_y(0); if (it->first == 0)
continue;
std::vector<std::string> link_urls;
base::android::AppendJavaStringArrayToStringVector(env, j_link_urls, skp_path =
&link_urls); path.AppendASCII(base::StrCat({it->second.guid.ToString(), ".skp"}));
std::vector<int> link_rects; it->second.proto.set_file_path(skp_path.AsUTF8Unsafe());
base::android::JavaIntArrayToIntVector(env, j_link_rects, &link_rects); *paint_preview.add_subframes() = it->second.proto;
for (size_t i = 0; i < link_urls.size(); ++i) { if (!WriteSkp(it->second.skp, skp_path, &(it->second.ctx)))
auto* link_proto = root_frame->add_links(); return false;
link_proto->set_url(link_urls[i]);
auto* rect = link_proto->mutable_rect();
rect->set_x(link_rects[i * 4]);
rect->set_y(link_rects[i * 4 + 1]);
rect->set_width(link_rects[i * 4 + 2]);
rect->set_height(link_rects[i * 4 + 3]);
} }
if (!WriteProtoToFile(path.AppendASCII("proto.pb"), paint_preview)) { if (!WriteProtoToFile(path.AppendASCII("proto.pb"), paint_preview)) {
LOG(ERROR) << "Failed to write proto to file."; LOG(ERROR) << "Failed to write proto to file.";
return false; return false;
} }
frames_.clear();
return true; return true;
} }
PaintPreviewTestService::Frame::Frame(const base::UnguessableToken& token)
: guid(token) {}
PaintPreviewTestService::Frame::~Frame() = default;
PaintPreviewTestService::Frame::Frame(Frame&& rhs) noexcept = default;
PaintPreviewTestService::Frame& PaintPreviewTestService::Frame::operator=(
Frame&& rhs) noexcept = default;
} // namespace paint_preview } // namespace paint_preview
...@@ -5,9 +5,13 @@ ...@@ -5,9 +5,13 @@
#ifndef COMPONENTS_PAINT_PREVIEW_PLAYER_ANDROID_JAVATESTS_PAINT_PREVIEW_TEST_SERVICE_H_ #ifndef COMPONENTS_PAINT_PREVIEW_PLAYER_ANDROID_JAVATESTS_PAINT_PREVIEW_TEST_SERVICE_H_
#define 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 "base/files/file_path.h"
#include "components/paint_preview/browser/paint_preview_base_service.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/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 { namespace paint_preview {
...@@ -20,17 +24,37 @@ class PaintPreviewTestService : public PaintPreviewBaseService { ...@@ -20,17 +24,37 @@ class PaintPreviewTestService : public PaintPreviewBaseService {
PaintPreviewTestService(const PaintPreviewTestService&) = delete; PaintPreviewTestService(const PaintPreviewTestService&) = delete;
PaintPreviewTestService& operator=(const PaintPreviewTestService&) = delete; PaintPreviewTestService& operator=(const PaintPreviewTestService&) = delete;
jboolean CreateSingleSkpForKey( base::android::ScopedJavaLocalRef<jintArray> CreateSingleSkp(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_key, jint j_id,
const base::android::JavaParamRef<jstring>& j_url,
jint j_width, jint j_width,
jint j_height, jint j_height,
const base::android::JavaParamRef<jintArray>& j_link_rects, 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: 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::FilePath test_data_dir_;
base::flat_map<uint32_t, Frame> frames_;
}; };
} // namespace paint_preview } // 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; ...@@ -9,6 +9,7 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.By; import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.UiObject2;
import android.util.Size;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
...@@ -85,13 +86,8 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -85,13 +86,8 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
destroyed.waitForFirst(); destroyed.waitForFirst();
} }
/** private void displayTest(boolean multipleFrames) {
* Tests the the player correctly initializes and displays a sample paint preview with 1 frame. initPlayerManager(multipleFrames);
*/
@Test
@MediumTest
public void singleFrameDisplayTest() {
initPlayerManager();
final View playerHostView = mPlayerManager.getView(); final View playerHostView = mPlayerManager.getView();
final View activityContentView = getActivity().findViewById(android.R.id.content); final View activityContentView = getActivity().findViewById(android.R.id.content);
...@@ -106,13 +102,32 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -106,13 +102,32 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
}, TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL); }, 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. * Tests that link clicks in the player work correctly.
*/ */
@Test @Test
@MediumTest @MediumTest
public void linkClickTest() { public void linkClickTest() {
initPlayerManager(); initPlayerManager(true);
final View playerHostView = mPlayerManager.getView(); final View playerHostView = mPlayerManager.getView();
// Click on a link that is visible in the default viewport. // Click on a link that is visible in the default viewport.
...@@ -131,7 +146,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -131,7 +146,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
@MediumTest @MediumTest
@DisabledTest(message = "https://crbug.com/1093083") @DisabledTest(message = "https://crbug.com/1093083")
public void overscrollRefreshTest() throws Exception { public void overscrollRefreshTest() throws Exception {
initPlayerManager(); initPlayerManager(true);
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
int deviceHeight = uiDevice.getDisplayHeight(); int deviceHeight = uiDevice.getDisplayHeight();
int statusBarHeight = statusBarHeight(); int statusBarHeight = statusBarHeight();
...@@ -174,7 +189,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -174,7 +189,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
@Test @Test
@MediumTest @MediumTest
public void scaleSmokeTest() throws Exception { public void scaleSmokeTest() throws Exception {
initPlayerManager(); initPlayerManager(true);
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// Query all FrameLayout objects as the PlayerFrameView isn't recognized. // Query all FrameLayout objects as the PlayerFrameView isn't recognized.
...@@ -239,7 +254,47 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -239,7 +254,47 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
uiDevice.swipe(50, fromY, 50, toY, swipeSteps); 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(); mLinkClickHandler = new TestLinkClickHandler();
mRefreshedCallback = new CallbackHelper(); mRefreshedCallback = new CallbackHelper();
CallbackHelper viewReady = new CallbackHelper(); CallbackHelper viewReady = new CallbackHelper();
...@@ -248,17 +303,16 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -248,17 +303,16 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
PaintPreviewTestService service = PaintPreviewTestService service =
new PaintPreviewTestService(mTempFolder.getRoot().getPath()); new PaintPreviewTestService(mTempFolder.getRoot().getPath());
Assert.assertTrue(service.createSingleSkpForKey(TEST_DIRECTORY_KEY, TEST_URL, if (multiSkp) {
TEST_PAGE_WIDTH, TEST_PAGE_HEIGHT, initMultiSkp(service);
new Rect[] {mInViewportLinkRect, mOutOfViewportLinkRect}, } else {
new String[] {TEST_IN_VIEWPORT_LINK_URL, TEST_OUT_OF_VIEWPORT_LINK_URL})); initSingleSkp(service);
}
mPlayerManager = new PlayerManager(new GURL(TEST_URL), getActivity(), service, mPlayerManager = new PlayerManager(new GURL(TEST_URL), getActivity(), service,
TEST_DIRECTORY_KEY, mLinkClickHandler, TEST_DIRECTORY_KEY, mLinkClickHandler, mRefreshedCallback::notifyCalled,
() viewReady::notifyCalled, null, 0xffffffff,
-> { mRefreshedCallback.notifyCalled(); }, () -> { mInitializationFailed = true; }, false);
()
-> { viewReady.notifyCalled(); },
null, 0xffffffff, () -> { mInitializationFailed = true; }, false);
mPlayerManager.setCompressOnClose(false); mPlayerManager.setCompressOnClose(false);
getActivity().setContentView(mPlayerManager.getView()); getActivity().setContentView(mPlayerManager.getView());
}); });
...@@ -285,6 +339,14 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase { ...@@ -285,6 +339,14 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
((ViewGroup) mPlayerManager.getView()).getChildCount(), ((ViewGroup) mPlayerManager.getView()).getChildCount(),
Matchers.greaterThan(0)); Matchers.greaterThan(0));
}, TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL); }, 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 @@ ...@@ -4,8 +4,6 @@
package org.chromium.components.paintpreview.player; package org.chromium.components.paintpreview.player;
import android.graphics.Rect;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
...@@ -28,35 +26,41 @@ public class PaintPreviewTestService implements NativePaintPreviewServiceProvide ...@@ -28,35 +26,41 @@ public class PaintPreviewTestService implements NativePaintPreviewServiceProvide
return mNativePaintPreviewTestService; return mNativePaintPreviewTestService;
} }
public boolean createSingleSkpForKey( public boolean createFramesForKey(String key, String url, FrameData rootFrameData) {
String key, String url, int width, int height, Rect[] linkRects, String[] links) {
if (mNativePaintPreviewTestService == 0) { if (mNativePaintPreviewTestService == 0) {
Log.e(TAG, "No native service."); Log.e(TAG, "No native service.");
return false; return false;
} }
assert linkRects.length == links.length; createFrames(rootFrameData, 0);
int flattenedRects[] = new int[linkRects.length * 4]; boolean ret = PaintPreviewTestServiceJni.get().serializeFrames(
for (int i = 0; i < linkRects.length; i++) { mNativePaintPreviewTestService, key, url);
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().createSingleSkpForKey(
mNativePaintPreviewTestService, key, url, width, height, flattenedRects, links);
if (!ret) { if (!ret) {
Log.e(TAG, "Native failed to setup files for testing."); Log.e(TAG, "Native failed to setup files for testing.");
} }
return ret; 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 @NativeMethods
interface Natives { interface Natives {
long getInstance(String path); long getInstance(String path);
boolean createSingleSkpForKey(long nativePaintPreviewTestService, String key, String url, int[] createSingleSkp(long nativePaintPreviewTestService, int id, int width, int height,
int width, int height, int[] flattenedRects, String[] links); 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