Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SurfaceProducer.Callback lifecycle hooks #53280

Merged
merged 14 commits into from
Jun 24, 2024
1 change: 1 addition & 0 deletions shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ embedding_dependencies_jars = [
"//third_party/android_embedding_dependencies/lib/lifecycle-common-java8-2.2.0.jar",
"//third_party/android_embedding_dependencies/lib/lifecycle-livedata-2.0.0.jar",
"//third_party/android_embedding_dependencies/lib/lifecycle-livedata-core-2.0.0.jar",
"//third_party/android_embedding_dependencies/lib/lifecycle-process-2.2.0.jar",
"//third_party/android_embedding_dependencies/lib/lifecycle-runtime-2.2.0.jar",
"//third_party/android_embedding_dependencies/lib/lifecycle-viewmodel-2.1.0.jar",
"//third_party/android_embedding_dependencies/lib/loader-1.0.0.jar",
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ android {
}
}

dependencies {
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary - do the new classes not resolve in android studio for you without it?

If they don't resolve without, I may need to revert #50840, I think something about that PR may have messed up how we resolve the android_embedding_dependencies jars

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, I'm not sure. I think this was auto-added by IntelliJ. Let me try removing and resyncing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears to work fine w/o, removing.

}

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.view.TextureRegistry;
Expand Down Expand Up @@ -78,6 +81,8 @@ public class FlutterRenderer implements TextureRegistry {
private final Set<WeakReference<TextureRegistry.OnTrimMemoryListener>> onTrimMemoryListeners =
new HashSet<>();

@NonNull private final List<ImageReaderSurfaceProducer> imageReaderProducers = new ArrayList<>();

@NonNull
private final FlutterUiDisplayListener flutterUiDisplayListener =
new FlutterUiDisplayListener() {
Expand All @@ -95,6 +100,20 @@ public void onFlutterUiNoLongerDisplayed() {
public FlutterRenderer(@NonNull FlutterJNI flutterJNI) {
this.flutterJNI = flutterJNI;
this.flutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
ProcessLifecycleOwner.get()
.getLifecycle()
.addObserver(
new DefaultLifecycleObserver() {
@Override
public void onResume(@NonNull LifecycleOwner owner) {
Log.w(TAG, "onResume called; notifying SurfaceProducers");
for (ImageReaderSurfaceProducer producer : imageReaderProducers) {
if (producer.callback != null) {
producer.callback.onSurfaceChanged();
}
}
}
});
}

/**
Expand Down Expand Up @@ -197,6 +216,7 @@ public SurfaceProducer createSurfaceProducer() {
final ImageReaderSurfaceProducer producer = new ImageReaderSurfaceProducer(id);
registerImageTexture(id, producer);
addOnTrimMemoryListener(producer);
imageReaderProducers.add(producer);
Log.v(TAG, "New ImageReaderSurfaceProducer ID: " + id);
entry = producer;
} else {
Expand Down Expand Up @@ -453,6 +473,7 @@ final class ImageReaderSurfaceProducer
new HashMap<ImageReader, PerImageReader>();
private PerImage lastDequeuedImage = null;
private PerImageReader lastReaderDequeuedFrom = null;
private Callback callback = null;

/** Internal class: state held per Image produced by ImageReaders. */
private class PerImage {
Expand Down Expand Up @@ -678,6 +699,7 @@ public void onTrimMemory(int level) {
private void releaseInternal() {
cleanup();
released = true;
imageReaderProducers.remove(this);
}

private void cleanup() {
Expand All @@ -699,6 +721,9 @@ private void cleanup() {
}
imageReaderQueue.clear();
}
if (this.callback != null) {
this.callback.onSurfaceDestroyed();
}
}

@TargetApi(API_LEVELS.API_33)
Expand Down Expand Up @@ -732,6 +757,11 @@ private void maybeWaitOnFence(Image image) {
this.id = id;
}

@Override
public void setCallback(Callback callback) {
this.callback = callback;
}

@Override
public long id() {
return id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public void release() {
released = true;
}

@Override
public void setCallback(Callback callback) {
// Intentionally blank: SurfaceTextures don't get platform notifications or cleanup.
}

@Override
@NonNull
public SurfaceTexture getSurfaceTexture() {
Expand Down
1 change: 1 addition & 0 deletions shell/platform/android/io/flutter/view/FlutterView.java
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,7 @@ public ImageTextureEntry createImageTexture() {
throw new UnsupportedOperationException("Image textures are not supported in this mode.");
}

@NonNull
@Override
public SurfaceProducer createSurfaceProducer() {
throw new UnsupportedOperationException(
Expand Down
52 changes: 45 additions & 7 deletions shell/platform/android/io/flutter/view/TextureRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ interface TextureEntry {
/** @return The identity of this texture. */
long id();

/** Deregisters and releases all resources . */
/** De-registers and releases all resources . */
void release();
}

Expand All @@ -79,18 +79,56 @@ interface SurfaceProducer extends TextureEntry {
int getHeight();

/**
* Get a Surface that can be used to update the texture contents.
* Direct access to the surface object.
*
* <p>NOTE: You should not cache the returned surface but instead invoke getSurface each time
* you need to draw. The surface may change when the texture is resized or has its format
* <p>When using this API, you will usually need to implement {@link SurfaceProducer.Callback}
* and provide it to {@link #setCallback(Callback)} in order to be notified when an existing
* surface has been destroyed (such as when the application goes to the background) or a new
* surface has been created (such as when the application is resumed back to the foreground).
*
* <p>NOTE: You should not cache the returned surface but instead invoke {@code getSurface} each
* time you need to draw. The surface may change when the texture is resized or has its format
* changed.
*
* @return a Surface to use for a drawing target for various APIs.
*/
Surface getSurface();

/**
* Sets a callback that is notified when a previously created {@link Surface} returned by {@link
* SurfaceProducer#getSurface()} is no longer valid, either due to being destroyed or being
* changed.
*
* @param callback The callback to notify, or null to remove the callback.
*/
void setCallback(Callback callback);

/** Callback invoked by {@link #setCallback(Callback)}. */
interface Callback {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming nit: Callbacks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* Invoked when a previous surface is now invalid and a new surface is now available.
*
* <p>Typically plugins will use this callback as a signal to redraw, such as due to the
* texture being resized, the format being changed, or the application being resumed after
* being suspended in the background.
*/
void onSurfaceChanged();
matanlurey marked this conversation as resolved.
Show resolved Hide resolved

/**
* Invoked when a previous surface is now invalid.
*
* <p>Typically plugins will use this callback as a signal to release resources.
*/
void onSurfaceDestroyed();
}

/**
* @deprecated This method is not officially part of the public API surface and will be removed.
*/
@Deprecated
@SuppressWarnings("DeprecatedIsStillUsed")
void scheduleFrame();
};
}

/** A registry entry for a managed SurfaceTexture. */
@Keep
Expand Down Expand Up @@ -144,7 +182,7 @@ interface ImageConsumer {
* @return Image or null.
*/
@Nullable
public Image acquireLatestImage();
Image acquireLatestImage();
}

@Keep
Expand All @@ -155,6 +193,6 @@ interface GLTextureConsumer {
* @return SurfaceTexture.
*/
@NonNull
public SurfaceTexture getSurfaceTexture();
SurfaceTexture getSurfaceTexture();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1582,13 +1582,16 @@ private static void attachToFlutterView(
new TextureRegistry() {
public void TextureRegistry() {}

@NonNull
@Override
public SurfaceTextureEntry createSurfaceTexture() {
return registerSurfaceTexture(mock(SurfaceTexture.class));
}

@NonNull
@Override
public SurfaceTextureEntry registerSurfaceTexture(SurfaceTexture surfaceTexture) {
public SurfaceTextureEntry registerSurfaceTexture(
@NonNull SurfaceTexture surfaceTexture) {
return new SurfaceTextureEntry() {
@NonNull
@Override
Expand All @@ -1606,6 +1609,7 @@ public void release() {}
};
}

@NonNull
@Override
public ImageTextureEntry createImageTexture() {
return new ImageTextureEntry() {
Expand All @@ -1622,9 +1626,13 @@ public void pushImage(Image image) {}
};
}

@NonNull
@Override
public SurfaceProducer createSurfaceProducer() {
return new SurfaceProducer() {
@Override
public void setCallback(SurfaceProducer.Callback cb) {}

@Override
public long id() {
return 0;
Expand Down
1 change: 1 addition & 0 deletions testing/scenario_app/android/app/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ androidx.lifecycle:lifecycle-common-java8:2.2.0=debugAndroidTestCompileClasspath
androidx.lifecycle:lifecycle-common:2.3.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.lifecycle:lifecycle-livedata-core:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.lifecycle:lifecycle-process:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.lifecycle:lifecycle-viewmodel:2.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
Expand Down
22 changes: 10 additions & 12 deletions tools/androidx/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
"url": "https://maven.google.com/androidx/lifecycle/lifecycle-common-java8/2.2.0/lifecycle-common-java8-2.2.0.jar",
"out_file_name": "androidx_lifecycle_common_java8.jar",
"maven_dependency": "androidx.lifecycle:lifecycle-common-java8:2.2.0",
"provides": [
"androidx.lifecycle.DefaultLifecycleObserver"
]
"provides": ["androidx.lifecycle.DefaultLifecycleObserver"]
},
{
"url": "https://maven.google.com/androidx/lifecycle/lifecycle-process/2.2.0/lifecycle-process-2.2.0.aar",
"out_file_name": "androidx_lifecycle_process.aar",
"maven_dependency": "androidx.lifecycle:lifecycle-process:2.2.0",
"provides": ["androidx.lifecycle.ProcessLifecycleOwner"]
},
{
"url": "https://maven.google.com/androidx/lifecycle/lifecycle-runtime/2.2.0/lifecycle-runtime-2.2.0.aar",
"out_file_name": "androidx_lifecycle_runtime.aar",
"maven_dependency": "androidx.lifecycle:lifecycle-runtime:2.2.0",
"provides": [
"androidx.lifecycle.LifecycleRegistry"
]
"provides": ["androidx.lifecycle.LifecycleRegistry"]
},
{
"url": "https://maven.google.com/androidx/fragment/fragment/1.1.0/fragment-1.1.0.aar",
Expand Down Expand Up @@ -54,17 +56,13 @@
"url": "https://maven.google.com/androidx/tracing/tracing/1.0.0/tracing-1.0.0.aar",
"out_file_name": "androidx_tracing.aar",
"maven_dependency": "androidx.tracing:tracing:1.0.0",
"provides": [
"androidx.tracing.Trace"
]
"provides": ["androidx.tracing.Trace"]
},
{
"url": "https://dl.google.com/android/maven2/androidx/core/core/1.6.0/core-1.6.0.aar",
"out_file_name": "androidx_core.aar",
"maven_dependency": "androidx.core:core:1.6.0",
"provides": [
"androidx.core.view.WindowInsetsControllerCompat"
]
"provides": ["androidx.core.view.WindowInsetsControllerCompat"]
},
{
"url": "https://maven.google.com/androidx/window/window-java/1.0.0-beta04/window-java-1.0.0-beta04.aar",
Expand Down
2 changes: 1 addition & 1 deletion tools/cipd/android_embedding_bundle/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:3.5.0"
classpath "com.android.tools.build:gradle:7.0.2"
}
}

Expand Down