未验证 提交 fb3e35d6 编写于 作者: M Matt Carroll 提交者: GitHub

Android Embedding PR15: Add Viewport Metrics to FlutterView (#8029)

上级 36ca5740
......@@ -56,6 +56,7 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "SurfaceHolder.Callback.surfaceChanged()");
if (isAttachedToFlutterRenderer) {
changeSurfaceSize(width, height);
}
......@@ -97,13 +98,17 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
* Invoked by the owner of this {@code FlutterSurfaceView} when it wants to begin rendering
* a Flutter UI to this {@code FlutterSurfaceView}.
*
* If an Android {@link android.view.Surface} is available, this method will begin rendering
* {@link FlutterRenderer}'s Flutter UI to this {@code FlutterSurfaceView}.
* If an Android {@link android.view.Surface} is available, this method will give that
* {@link android.view.Surface} to the given {@link FlutterRenderer} to begin rendering
* Flutter's UI to this {@code FlutterSurfaceView}.
*
* If no Android {@link android.view.Surface} is available yet, this {@code FlutterSurfaceView}
* will wait until a {@link android.view.Surface} becomes available and then begin rendering.
* will wait until a {@link android.view.Surface} becomes available and then give that
* {@link android.view.Surface} to the given {@link FlutterRenderer} to begin rendering
* Flutter's UI to this {@code FlutterSurfaceView}.
*/
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
Log.d(TAG, "attachToRenderer");
if (this.flutterRenderer != null) {
this.flutterRenderer.detachFromRenderSurface();
}
......@@ -114,6 +119,7 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
// If we're already attached to an Android window then we're now attached to both a renderer
// and the Android window. We can begin rendering now.
if (isSurfaceAvailableForRendering) {
Log.d(TAG, "Surface is available for rendering. Connecting.");
connectSurfaceToRenderer();
}
}
......@@ -179,5 +185,6 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
@Override
public void onFirstFrameRendered() {
// TODO(mattcarroll): decide where this method should live and what it needs to do.
Log.d(TAG, "onFirstFrameRendered()");
}
}
......@@ -111,11 +111,14 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
* Invoked by the owner of this {@code FlutterTextureView} when it wants to begin rendering
* a Flutter UI to this {@code FlutterTextureView}.
*
* If an Android {@link SurfaceTexture} is available, this method will begin rendering
* {@link FlutterRenderer}'s Flutter UI to this {@code FlutterTextureView}.
* If an Android {@link SurfaceTexture} is available, this method will give that
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
* Flutter's UI to this {@code FlutterTextureView}.
*
* If no Android {@link SurfaceTexture} is available yet, this {@code FlutterSurfaceView}
* will wait until a {@link SurfaceTexture} becomes available and then begin rendering.
* If no Android {@link SurfaceTexture} is available yet, this {@code FlutterTextureView}
* will wait until a {@link SurfaceTexture} becomes available and then give that
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
* Flutter's UI to this {@code FlutterTextureView}.
*/
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
if (this.flutterRenderer != null) {
......@@ -193,5 +196,6 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
@Override
public void onFirstFrameRendered() {
// TODO(mattcarroll): decide where this method should live and what it needs to do.
Log.d(TAG, "onFirstFrameRendered()");
}
}
......@@ -17,10 +17,9 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import java.util.ArrayList;
......@@ -30,6 +29,7 @@ import java.util.Locale;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.view.VsyncWaiter;
/**
* Displays a Flutter UI on an Android device.
......@@ -77,6 +77,9 @@ public class FlutterView extends FrameLayout {
@Nullable
private AndroidKeyProcessor androidKeyProcessor;
// Directly implemented View behavior that communicates with Flutter.
private final FlutterRenderer.ViewportMetrics viewportMetrics = new FlutterRenderer.ViewportMetrics();
/**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes.
*
......@@ -158,8 +161,10 @@ public class FlutterView extends FrameLayout {
*/
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
// TODO(mattcarroll): hookup to viewport metrics.
super.onSizeChanged(width, height, oldWidth, oldHeight);
viewportMetrics.width = width;
viewportMetrics.height = height;
sendViewportMetricsToFlutter();
}
/**
......@@ -174,8 +179,22 @@ public class FlutterView extends FrameLayout {
*/
@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
// TODO(mattcarroll): hookup to Flutter metrics.
return insets;
WindowInsets newInsets = super.onApplyWindowInsets(insets);
// Status bar (top) and left/right system insets should partially obscure the content (padding).
viewportMetrics.paddingTop = insets.getSystemWindowInsetTop();
viewportMetrics.paddingRight = insets.getSystemWindowInsetRight();
viewportMetrics.paddingBottom = 0;
viewportMetrics.paddingLeft = insets.getSystemWindowInsetLeft();
// Bottom system inset (keyboard) should adjust scrollable bottom edge (inset).
viewportMetrics.viewInsetTop = 0;
viewportMetrics.viewInsetRight = 0;
viewportMetrics.viewInsetBottom = insets.getSystemWindowInsetBottom();
viewportMetrics.viewInsetLeft = 0;
sendViewportMetricsToFlutter();
return newInsets;
}
/**
......@@ -188,8 +207,23 @@ public class FlutterView extends FrameLayout {
@Override
@SuppressWarnings("deprecation")
protected boolean fitSystemWindows(Rect insets) {
// TODO(mattcarroll): hookup to Flutter metrics.
return super.fitSystemWindows(insets);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
// Status bar, left/right system insets partially obscure content (padding).
viewportMetrics.paddingTop = insets.top;
viewportMetrics.paddingRight = insets.right;
viewportMetrics.paddingBottom = 0;
viewportMetrics.paddingLeft = insets.left;
// Bottom system inset (keyboard) should adjust scrollable bottom edge (inset).
viewportMetrics.viewInsetTop = 0;
viewportMetrics.viewInsetRight = 0;
viewportMetrics.viewInsetBottom = insets.bottom;
viewportMetrics.viewInsetLeft = 0;
sendViewportMetricsToFlutter();
return true;
} else {
return super.fitSystemWindows(insets);
}
}
//------- End: Process View configuration that Flutter cares about. --------
......@@ -312,13 +346,16 @@ public class FlutterView extends FrameLayout {
* {@link FlutterEngine}.
*/
public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
Log.d(TAG, "attachToFlutterEngine()");
if (isAttachedToFlutterEngine()) {
if (flutterEngine == this.flutterEngine) {
// We are already attached to this FlutterEngine
Log.d(TAG, "Already attached to this engine. Doing nothing.");
return;
}
// Detach from a previous FlutterEngine so we can attach to this new one.
Log.d(TAG, "Currently attached to a different engine. Detaching.");
detachFromFlutterEngine();
}
......@@ -346,6 +383,7 @@ public class FlutterView extends FrameLayout {
// Push View and Context related information from Android to Flutter.
sendUserSettingsToFlutter();
sendLocalesToFlutter(getResources().getConfiguration());
sendViewportMetricsToFlutter();
}
/**
......@@ -359,7 +397,9 @@ public class FlutterView extends FrameLayout {
* {@link FlutterEngine}.
*/
public void detachFromFlutterEngine() {
Log.d(TAG, "detachFromFlutterEngine()");
if (!isAttachedToFlutterEngine()) {
Log.d(TAG, "Not attached to an engine. Doing nothing.");
return;
}
Log.d(TAG, "Detaching from Flutter Engine");
......@@ -422,6 +462,18 @@ public class FlutterView extends FrameLayout {
.send();
}
// TODO(mattcarroll): consider introducing a system channel for this communication instead of JNI
private void sendViewportMetricsToFlutter() {
Log.d(TAG, "sendViewportMetricsToFlutter()");
if (!isAttachedToFlutterEngine()) {
Log.w(TAG, "Tried to send viewport metrics from Android to Flutter but this FlutterView was not attached to a FlutterEngine.");
return;
}
viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density;
flutterEngine.getRenderer().setViewportMetrics(viewportMetrics);
}
/**
* Render modes for a {@link FlutterView}.
*/
......
......@@ -29,7 +29,7 @@ import io.flutter.view.TextureRegistry;
* code via JNI. The corresponding {@link RenderSurface} is used as a delegate to carry out
* certain actions on behalf of this {@code FlutterRenderer} within an Android view hierarchy.
*
* {@link FlutterView} is an implementation of a {@link RenderSurface}.
* {@link io.flutter.embedding.engine.android.FlutterView} is an implementation of a {@link RenderSurface}.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class FlutterRenderer implements TextureRegistry {
......@@ -49,14 +49,16 @@ public class FlutterRenderer implements TextureRegistry {
}
this.renderSurface = renderSurface;
this.renderSurface.attachToRenderer(this);
this.flutterJNI.setRenderSurface(renderSurface);
}
public void detachFromRenderSurface() {
// TODO(mattcarroll): determine desired behavior if we're asked to detach without first being attached
if (this.renderSurface != null) {
surfaceDestroyed();
this.renderSurface.detachFromRenderer();
this.renderSurface = null;
surfaceDestroyed();
this.flutterJNI.setRenderSurface(null);
}
}
......@@ -157,29 +159,19 @@ public class FlutterRenderer implements TextureRegistry {
}
// TODO(mattcarroll): describe the native behavior that this invokes
public void setViewportMetrics(float devicePixelRatio,
int physicalWidth,
int physicalHeight,
int physicalPaddingTop,
int physicalPaddingRight,
int physicalPaddingBottom,
int physicalPaddingLeft,
int physicalViewInsetTop,
int physicalViewInsetRight,
int physicalViewInsetBottom,
int physicalViewInsetLeft) {
public void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics) {
flutterJNI.setViewportMetrics(
devicePixelRatio,
physicalWidth,
physicalHeight,
physicalPaddingTop,
physicalPaddingRight,
physicalPaddingBottom,
physicalPaddingLeft,
physicalViewInsetTop,
physicalViewInsetRight,
physicalViewInsetBottom,
physicalViewInsetLeft
viewportMetrics.devicePixelRatio,
viewportMetrics.width,
viewportMetrics.height,
viewportMetrics.paddingTop,
viewportMetrics.paddingRight,
viewportMetrics.paddingBottom,
viewportMetrics.paddingLeft,
viewportMetrics.viewInsetTop,
viewportMetrics.viewInsetRight,
viewportMetrics.viewInsetBottom,
viewportMetrics.viewInsetLeft
);
}
......@@ -281,4 +273,24 @@ public class FlutterRenderer implements TextureRegistry {
*/
void onFirstFrameRendered();
}
/**
* Mutable data structure that holds all viewport metrics properties that Flutter cares about.
*
* All distance measurements, e.g., width, height, padding, viewInsets, are measured in device
* pixels, not logical pixels.
*/
public static final class ViewportMetrics {
public float devicePixelRatio = 1.0f;
public int width = 0;
public int height = 0;
public int paddingTop = 0;
public int paddingRight = 0;
public int paddingBottom = 0;
public int paddingLeft = 0;
public int viewInsetTop = 0;
public int viewInsetRight = 0;
public int viewInsetBottom = 0;
public int viewInsetLeft = 0;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册