blob: 2cf41f1f87a7962df6703020442f47ffac70bcda [file] [log] [blame]
// Copyright 2019 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 androidx.test.espresso.flutter.internal.protocol.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import android.util.Log;
import android.view.View;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.dart.DartExecutor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
/** Util class for dealing with Dart VM service protocols. */
public final class DartVmServiceUtil {
private static final String TAG = DartVmServiceUtil.class.getSimpleName();
/**
* Converts the Dart VM observatory http server URL to the service protocol WebSocket URL.
*
* @param observatoryUrl The Dart VM http server URL that can be converted to a service protocol
* URI.
*/
public static URI getServiceProtocolUri(String observatoryUrl) {
if (isNullOrEmpty(observatoryUrl)) {
throw new RuntimeException(
"Dart VM Observatory is not enabled. "
+ "Please make sure your Flutter app is running under debug mode.");
}
try {
new URL(observatoryUrl);
} catch (MalformedURLException e) {
throw new RuntimeException(
String.format("Dart VM Observatory url %s is malformed.", observatoryUrl), e);
}
// Constructs the service protocol URL based on the Observatory http url.
// For example, http://127.0.0.1:39694/qsnVeidc78Y=/ -> ws://127.0.0.1:39694/qsnVeidc78Y=/ws.
int schemaIndex = observatoryUrl.indexOf(":");
String serviceProtocolUri = "ws" + observatoryUrl.substring(schemaIndex);
if (!observatoryUrl.endsWith("/")) {
serviceProtocolUri += "/";
}
serviceProtocolUri += "ws";
Log.i(TAG, "Dart VM service protocol runs at uri: " + serviceProtocolUri);
try {
return new URI(serviceProtocolUri);
} catch (URISyntaxException e) {
// Should never happen.
throw new RuntimeException("Illegal Dart VM service protocol URI: " + serviceProtocolUri, e);
}
}
/** Gets the Dart isolate ID for the given {@code flutterView}. */
public static String getDartIsolateId(View flutterView) {
checkNotNull(flutterView, "The Flutter View instance cannot be null.");
String uiIsolateId = getDartExecutor(flutterView).getIsolateServiceId();
Log.d(
TAG,
String.format(
"Dart isolate ID for the Flutter View [id: %d]: %s.",
flutterView.getId(), uiIsolateId));
return uiIsolateId;
}
/** Gets the Dart executor for the given {@code flutterView}. */
public static DartExecutor getDartExecutor(View flutterView) {
checkNotNull(flutterView, "The Flutter View instance cannot be null.");
// Flutter's embedding is in the phase of rewriting/refactoring. Let's be compatible with both
// the old and the new FlutterView classes.
if (flutterView instanceof io.flutter.view.FlutterView) {
return ((io.flutter.view.FlutterView) flutterView).getDartExecutor();
} else if (flutterView instanceof io.flutter.embedding.android.FlutterView) {
FlutterEngine flutterEngine =
((io.flutter.embedding.android.FlutterView) flutterView).getAttachedFlutterEngine();
if (flutterEngine == null) {
throw new FlutterProtocolException(
String.format(
"No Flutter engine attached to the Flutter view [id: %d].", flutterView.getId()));
}
return flutterEngine.getDartExecutor();
} else {
throw new FlutterProtocolException(
String.format("This is not a Flutter View instance [id: %d].", flutterView.getId()));
}
}
}