зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1707959 - Set TYPE_GLOW overscroll type on Android 12. r=droeh
Android 12 introduces a new type of overscroll effect named TYPE_STRETCH which stretches the whole surface when overscrolling. Unforunately, given how it's implemented, SurfaceView does not support this type of effect, similarly to many other View effects. The OverscrollEffect is currently crashing on Android 12 builds so we restore the type to the previous (and only) default to fix the crash. Note that Overscroll is still not displayed, I'll open a new bug to fix that part. This patch also avoids using reflection for setBlendMode on API 29 and later where an API is actually available. Using reflection to access private APIs is not available since Android 9 so this code was a no-op before this patch. Differential Revision: https://phabricator.services.mozilla.com/D115031
This commit is contained in:
Родитель
6c4f65174f
Коммит
96274c4ba9
|
@ -8,6 +8,7 @@ package org.mozilla.geckoview;
|
|||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
|
@ -17,9 +18,11 @@ import android.os.Build;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import android.widget.EdgeEffect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@UiThread
|
||||
public final class OverscrollEdgeEffect {
|
||||
|
@ -44,6 +47,61 @@ public final class OverscrollEdgeEffect {
|
|||
mSession = session;
|
||||
}
|
||||
|
||||
private static Field sPaintField;
|
||||
private static Method sSetType;
|
||||
|
||||
// By default on SDK_INT 31 and above the edge effect default changed to "TYPE_STRETCH"
|
||||
// which is an effect that we can't support due to using SurfaceTexture.
|
||||
// This restores the edge effect type to TYPE_GLOW which is the default (and only option) on
|
||||
// lower versions.
|
||||
private void setType(final EdgeEffect edgeEffect) {
|
||||
if (Build.VERSION.SDK_INT < 31 && !Build.VERSION.CODENAME.equals("S")) {
|
||||
// setType is only available on 31 (early builds advertise themselves as 30,
|
||||
// with codename S)
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: remove reflection once 31 is stable
|
||||
if (sSetType == null) {
|
||||
try {
|
||||
sSetType = EdgeEffect.class.getDeclaredMethod("setType", int.class);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
// Nothing we can do here
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sSetType.invoke(edgeEffect, /* TYPE_GLOW */ 0);
|
||||
} catch (final Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private void setBlendMode(final EdgeEffect edgeEffect) {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
edgeEffect.setBlendMode(BlendMode.SRC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sPaintField == null) {
|
||||
try {
|
||||
sPaintField = EdgeEffect.class.getDeclaredField("mPaint");
|
||||
sPaintField.setAccessible(true);
|
||||
} catch (final NoSuchFieldException e) {
|
||||
// Cannot get the field, nothing we can do here
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final Paint paint = (Paint) sPaintField.get(edgeEffect);
|
||||
final PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
|
||||
paint.setXfermode(mode);
|
||||
} catch (final IllegalAccessException ex) {
|
||||
// Nothing we can do
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme to use for overscroll from a given Context.
|
||||
*
|
||||
|
@ -52,34 +110,11 @@ public final class OverscrollEdgeEffect {
|
|||
public void setTheme(final @NonNull Context context) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
|
||||
Field paintField = null;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
try {
|
||||
paintField = EdgeEffect.class.getDeclaredField("mPaint");
|
||||
paintField.setAccessible(true);
|
||||
} catch (final NoSuchFieldException e) {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mEdges.length; i++) {
|
||||
mEdges[i] = new EdgeEffect(context);
|
||||
|
||||
if (paintField == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final Paint p = (Paint) paintField.get(mEdges[i]);
|
||||
|
||||
// The Android EdgeEffect class uses a mode of SRC_ATOP here, which means
|
||||
// it will only draw the effect where there are non-transparent pixels in
|
||||
// the destination. Since the LayerView itself is fully transparent, it
|
||||
// doesn't display at all. We need to use SRC instead.
|
||||
p.setXfermode(mode);
|
||||
} catch (final IllegalAccessException e) {
|
||||
}
|
||||
final EdgeEffect edgeEffect = new EdgeEffect(context);
|
||||
setBlendMode(edgeEffect);
|
||||
setType(edgeEffect);
|
||||
mEdges[i] = edgeEffect;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче