mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1780093 - Use custom SurfaceView which allows magnifier widget to work. r=geckoview-reviewers,owlish
The android magnifier widget does not work when using our SurfaceControl rendering path, as we no longer render in to the Surface provided by the SurfaceView, but instead into a child Surface we have created and attached the SurfaceControl. To fix this, we create a SurfaceView subclass, MagnifiableSurfaceView, which allows us to set an override Surface to be used by the magnifier. This class works by overriding getHolder() to return a custom SurfaceHolder, which returns our override Surface rather than the default one when called by the Magnifier class. Depends on D157308 Differential Revision: https://phabricator.services.mozilla.com/D157309
This commit is contained in:
parent
5e60f35505
commit
49c0f0ed43
@ -0,0 +1,137 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
/**
|
||||
* A {@link android.view.SurfaceView} which allows a {@link android.widget.Magnifier} widget to
|
||||
* magnify a custom {@link android.view.Surface} rather than the SurfaceView's default Surface.
|
||||
*/
|
||||
public class MagnifiableSurfaceView extends SurfaceView {
|
||||
private static final String LOGTAG = "MagnifiableSurfaceView";
|
||||
|
||||
private SurfaceHolderWrapper mHolder;
|
||||
|
||||
public MagnifiableSurfaceView(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceHolder getHolder() {
|
||||
if (mHolder != null) {
|
||||
// Only return our custom holder if we are being called from the Magnifier class.
|
||||
// Throwable.getStackTrace() is faster than Thread.getStackTrace(), but still has a cost,
|
||||
// hence why we only check the caller if we have set an override Surface.
|
||||
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
|
||||
if (stackTrace.length >= 2
|
||||
&& stackTrace[1].getClassName().equals("android.widget.Magnifier")) {
|
||||
return mHolder;
|
||||
}
|
||||
}
|
||||
return super.getHolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Surface that should be magnified by a Magnifier widget.
|
||||
*
|
||||
* <p>This should be set immediately before calling {@link android.widget.Magnifier#show()} or
|
||||
* {@link android.widget.Magnifier#update()}, and unset immediately afterwards.
|
||||
*
|
||||
* @param surface The Surface to be magnified. If null, the SurfaceView's default Surface will be
|
||||
* used.
|
||||
*/
|
||||
public void setMagnifierSurface(final Surface surface) {
|
||||
if (surface != null) {
|
||||
mHolder = new SurfaceHolderWrapper(getHolder(), surface);
|
||||
} else {
|
||||
mHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link android.view.SurfaceHolder} implementation that simply forwards all methods to a
|
||||
* provided SurfaceHolder instance, except for getSurface() which returns a custom Surface.
|
||||
*/
|
||||
private class SurfaceHolderWrapper implements SurfaceHolder {
|
||||
private final SurfaceHolder mHolder;
|
||||
private final Surface mSurface;
|
||||
|
||||
public SurfaceHolderWrapper(final SurfaceHolder holder, final Surface surface) {
|
||||
mHolder = holder;
|
||||
mSurface = surface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(final Callback callback) {
|
||||
mHolder.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(final Callback callback) {
|
||||
mHolder.removeCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreating() {
|
||||
return mHolder.isCreating();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(final int type) {
|
||||
mHolder.setType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFixedSize(final int width, final int height) {
|
||||
mHolder.setFixedSize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSizeFromLayout() {
|
||||
mHolder.setSizeFromLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFormat(final int format) {
|
||||
mHolder.setFormat(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeepScreenOn(final boolean screenOn) {
|
||||
mHolder.setKeepScreenOn(screenOn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Canvas lockCanvas() {
|
||||
return mHolder.lockCanvas();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Canvas lockCanvas(final Rect dirty) {
|
||||
return mHolder.lockCanvas(dirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockCanvasAndPost(final Canvas canvas) {
|
||||
mHolder.unlockCanvasAndPost(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rect getSurfaceFrame() {
|
||||
return mHolder.getSurfaceFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Surface getSurface() {
|
||||
return mSurface;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public class SurfaceViewWrapper {
|
||||
}
|
||||
|
||||
private void initSurfaceView(final Context context) {
|
||||
mSurfaceView = new SurfaceView(context);
|
||||
mSurfaceView = new MagnifiableSurfaceView(context);
|
||||
mSurfaceView.setBackgroundColor(Color.TRANSPARENT);
|
||||
mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
|
||||
mView = mSurfaceView;
|
||||
|
@ -28,6 +28,7 @@ import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewStructure;
|
||||
import android.view.inputmethod.CursorAnchorInfo;
|
||||
@ -68,6 +69,7 @@ import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoThread;
|
||||
import org.mozilla.gecko.IGeckoEditableParent;
|
||||
import org.mozilla.gecko.MagnifiableSurfaceView;
|
||||
import org.mozilla.gecko.NativeQueue;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.mozglue.JNIObject;
|
||||
@ -170,9 +172,14 @@ public class GeckoSession {
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
private static class SessionMagnifierP implements GeckoSession.SessionMagnifier {
|
||||
private class SessionMagnifierP implements GeckoSession.SessionMagnifier {
|
||||
private @Nullable View mView;
|
||||
private @Nullable Magnifier mMagnifier;
|
||||
private final @NonNull Compositor mCompositor;
|
||||
|
||||
private SessionMagnifierP(final Compositor compositor) {
|
||||
mCompositor = compositor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
@ -206,7 +213,15 @@ public class GeckoSession {
|
||||
mMagnifier = new Magnifier(mView);
|
||||
}
|
||||
|
||||
if (mView instanceof MagnifiableSurfaceView) {
|
||||
final MagnifiableSurfaceView view = (MagnifiableSurfaceView) mView;
|
||||
view.setMagnifierSurface(mCompositor.getMagnifiableSurface());
|
||||
}
|
||||
mMagnifier.show(sourceCenter.x, sourceCenter.y);
|
||||
if (mView instanceof MagnifiableSurfaceView) {
|
||||
final MagnifiableSurfaceView view = (MagnifiableSurfaceView) mView;
|
||||
view.setMagnifierSurface(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -311,6 +326,12 @@ public class GeckoSession {
|
||||
public native void syncResumeResizeCompositor(
|
||||
int x, int y, int width, int height, Object surface, Object surfaceControl);
|
||||
|
||||
// Returns a Surface that content has been rendered in to, which should be used when the
|
||||
// magnifier is shown. This may differ from the Surface we have passed to
|
||||
// syncResumeResizeCompositor().
|
||||
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
|
||||
public native Surface getMagnifiableSurface();
|
||||
|
||||
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
|
||||
public native void setMaxToolbarHeight(int height);
|
||||
|
||||
@ -1632,7 +1653,7 @@ public class GeckoSession {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
if (mMagnifier == null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
mMagnifier = new SessionMagnifierP();
|
||||
mMagnifier = new SessionMagnifierP(mCompositor);
|
||||
} else {
|
||||
mMagnifier = new SessionMagnifier() {};
|
||||
}
|
||||
|
@ -1309,6 +1309,10 @@ class LayerViewSupport final
|
||||
MakeUnique<LayerViewEvent>(MakeUnique<OnResumedEvent>(aObj)));
|
||||
}
|
||||
|
||||
mozilla::jni::Object::LocalRef GetMagnifiableSurface() {
|
||||
return mozilla::jni::Object::LocalRef::From(GetSurface());
|
||||
}
|
||||
|
||||
void SyncInvalidateAndScheduleComposite() {
|
||||
if (!mUiCompositorControllerChild) {
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user