Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ deps = {
'packages': [
{
'package': 'flutter/android/embedding_bundle',
'version': 'last_updated:2023-08-11T11:35:44-0700'
'version': 'last_updated:2024-06-12T14:15:49-0700'
}
],
'condition': 'download_android_deps',
Expand Down
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
1 change: 0 additions & 1 deletion shell/platform/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,3 @@ android {
implementation "org.mockito:mockito-android:$mockitoVersion"
}
}

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.v(TAG, "onResume called; notifying SurfaceProducers");
for (ImageReaderSurfaceProducer producer : imageReaderProducers) {
if (producer.callback != null) {
producer.callback.onSurfaceCreated();
}
}
}
});
}

/**
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 @@ -673,11 +694,15 @@ public void onTrimMemory(int level) {
}
cleanup();
createNewReader = true;
if (this.callback != null) {
this.callback.onSurfaceDestroyed();
}
}

private void releaseInternal() {
cleanup();
released = true;
imageReaderProducers.remove(this);
}

private void cleanup() {
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
48 changes: 41 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,52 @@ 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 onSurfaceCreated();

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

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

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

@Keep
Expand All @@ -155,6 +189,6 @@ interface GLTextureConsumer {
* @return SurfaceTexture.
*/
@NonNull
public SurfaceTexture getSurfaceTexture();
SurfaceTexture getSurfaceTexture();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import android.os.Looper;
import android.view.Surface;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.android.FlutterActivity;
Expand Down Expand Up @@ -728,8 +730,46 @@ public void SurfaceTextureSurfaceProducerCreatesAConnectedTexture() {
}

@Test
public void CanLaunchActivityUsingFlutterEngine() {
// This is a placeholder test that will be used to test lifecycle events w/ SurfaceProducer.
scenarioRule.getScenario().moveToState(Lifecycle.State.RESUMED);
public void ImageReaderSurfaceProducerIsDestroyedOnTrimMemory() {
FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();

// Create and set a mock callback.
TextureRegistry.SurfaceProducer.Callback callback =
mock(TextureRegistry.SurfaceProducer.Callback.class);
producer.setCallback(callback);

// Trim memory.
((FlutterRenderer.ImageReaderSurfaceProducer) producer).onTrimMemory(40);

// Verify.
verify(callback).onSurfaceDestroyed();
}

@Test
public void ImageReaderSurfaceProducerIsCreatedOnLifecycleResume() throws Exception {
FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();

// Create a callback.
CountDownLatch latch = new CountDownLatch(1);
TextureRegistry.SurfaceProducer.Callback callback =
new TextureRegistry.SurfaceProducer.Callback() {
@Override
public void onSurfaceCreated() {
latch.countDown();
}

@Override
public void onSurfaceDestroyed() {}
};
producer.setCallback(callback);

// Trigger a resume.
((LifecycleRegistry) ProcessLifecycleOwner.get().getLifecycle())
.setCurrentState(Lifecycle.State.RESUMED);

// Verify.
latch.await();
}
}
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