未验证 提交 8c02e389 编写于 作者: E Emmanuel Garcia 提交者: GitHub

Prepare scenario app to run on Android emulator on LUCI (#20350)

上级 0cf4809e
......@@ -13,7 +13,6 @@ import android.os.Looper;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnitRunner;
import androidx.test.runner.screenshot.Screenshot;
import com.facebook.testing.screenshot.ScreenshotRunner;
import com.facebook.testing.screenshot.internal.AlbumImpl;
import com.facebook.testing.screenshot.internal.Registry;
......@@ -164,8 +163,6 @@ public class ScreenshotUtil {
// This method is called from the runner thread,
// so block the UI thread while taking the screenshot.
// UiThreadLocker locker = new UiThreadLocker();
// locker.lock();
// Screenshot.capture(view or activity) does not capture the Flutter UI.
// Unfortunately, it doesn't work with Android's `Surface` or `TextureSurface`.
......@@ -182,7 +179,8 @@ public class ScreenshotUtil {
new Callable<Void>() {
@Override
public Void call() {
Bitmap bitmap = Screenshot.capture().getBitmap();
Bitmap bitmap =
InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
// Remove the status and action bars from the screenshot capture.
bitmap =
Bitmap.createBitmap(
......
......@@ -4,27 +4,34 @@
package dev.flutter.scenarios;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import java.util.concurrent.atomic.AtomicBoolean;
public class TestableFlutterActivity extends FlutterActivity {
private Object flutterUiRenderedLock;
private Object flutterUiRenderedLock = new Object();
private AtomicBoolean isScenarioReady = new AtomicBoolean(false);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Reset the lock.
flutterUiRenderedLock = new Object();
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
flutterEngine
.getDartExecutor()
.setMessageHandler("take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered());
}
protected void notifyFlutterRendered() {
synchronized (flutterUiRenderedLock) {
isScenarioReady.set(true);
flutterUiRenderedLock.notifyAll();
}
}
public void waitUntilFlutterRendered() {
try {
if (isScenarioReady.get()) {
return;
}
synchronized (flutterUiRenderedLock) {
flutterUiRenderedLock.wait();
}
......
......@@ -12,7 +12,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
......@@ -71,6 +70,7 @@ public class TextPlatformViewActivity extends TestableFlutterActivity {
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
flutterEngine
.getPlatformViewsController()
.getRegistry()
......@@ -89,22 +89,6 @@ public class TextPlatformViewActivity extends TestableFlutterActivity {
test.put("name", launchIntent.getStringExtra("scenario"));
test.put("use_android_view", launchIntent.getBooleanExtra("use_android_view", false));
channel.invokeMethod("set_scenario", test);
notifyFlutterRenderedAfterVsync();
}
private void notifyFlutterRenderedAfterVsync() {
// Wait 1s after the next frame, so the Android texture are rendered.
Choreographer.getInstance()
.postFrameCallbackDelayed(
new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
reportFullyDrawn();
notifyFlutterRendered();
}
},
1000L);
}
private void writeTimelineData(Uri logFile) {
......
#!/bin/sh
#!/bin/bash
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
......
......@@ -28,6 +28,16 @@ echo "Using dart from $HOST_TOOLS, gen_snapshot from $DEVICE_TOOLS."
OUTDIR="${BASH_SOURCE%/*}/build/app"
FLUTTER_ASSETS_DIR=$OUTDIR/assets/flutter_assets
LIBS_DIR="${BASH_SOURCE%/*}/android/app/libs"
GEN_SNAPSHOT=$DEVICE_TOOLS/gen_snapshot
if [[ ! -f "$GEN_SNAPSHOT" ]]; then
GEN_SNAPSHOT=$DEVICE_TOOLS/gen_snapshot_host_targeting_host
fi
if [[ ! -f "$GEN_SNAPSHOT" ]]; then
echo "Could not find gen_snapshot in $DEVICE_TOOLS."
exit 1
fi
echo "Creating directories..."
......@@ -47,7 +57,7 @@ echo "Compiling kernel..."
echo "Compiling JIT Snapshot..."
"$DEVICE_TOOLS/gen_snapshot" --deterministic \
"$GEN_SNAPSHOT" --deterministic \
--enable-asserts \
--no-causal_async_stacks \
--lazy_async_stacks \
......
......@@ -90,6 +90,14 @@ Future<Map<String, dynamic>> _getJson(Uri uri) async {
void _onBeginFrame(Duration duration) {
currentScenario?.onBeginFrame(duration);
// Render an empty frame to signal first frame in the platform side.
if (currentScenario == null) {
final SceneBuilder builder = SceneBuilder();
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}
}
void _onDrawFrame() {
......
......@@ -9,11 +9,14 @@ import 'dart:ui';
/// A scenario to run for testing.
abstract class Scenario {
/// Creates a new scenario using a specific Window instance.
const Scenario(this.window);
Scenario(this.window);
/// The window used by this scenario. May be mocked.
final Window window;
/// [true] if a screenshot is taken in the next frame.
bool _didScheduleScreenshot = false;
/// Called by the program when a frame is ready to be drawn.
///
/// See [Window.onBeginFrame] for more details.
......@@ -23,7 +26,22 @@ abstract class Scenario {
/// flushed.
///
/// See [Window.onDrawFrame] for more details.
void onDrawFrame() {}
void onDrawFrame() {
Future<void>.delayed(const Duration(seconds: 1), () {
if (_didScheduleScreenshot) {
window.sendPlatformMessage('take_screenshot', null, null);
} else {
_didScheduleScreenshot = true;
window.scheduleFrame();
}
});
}
/// Called when the current scenario has been unmount due to a
/// new scenario being mount.
void unmount() {
_didScheduleScreenshot = false;
}
/// Called by the program when the window metrics have changed.
///
......
......@@ -43,11 +43,9 @@ Map<String, ScenarioFactory> _scenarios = <String, ScenarioFactory>{
'text_semantics_focus': () => SendTextFocusScemantics(window),
};
Map<String, dynamic> _currentScenarioParams = <String, dynamic>{
'name': 'animated_color_square',
};
Map<String, dynamic> _currentScenarioParams = <String, dynamic>{};
Scenario _currentScenarioInstance = _scenarios[_currentScenarioParams['name']]();
Scenario _currentScenarioInstance;
/// Loads an scenario.
/// The map must contain a `name` entry, which equals to the name of the scenario.
......@@ -55,6 +53,11 @@ void loadScenario(Map<String, dynamic> scenario) {
final String scenarioName = scenario['name'] as String;
assert(_scenarios[scenarioName] != null);
_currentScenarioParams = scenario;
if (_currentScenarioInstance != null) {
_currentScenarioInstance.unmount();
}
_currentScenarioInstance = _scenarios[scenario['name']]();
window.scheduleFrame();
print('Loading scenario $scenarioName');
......
#!/bin/sh
#!/bin/bash
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册