Loading core/java/android/app/UiAutomationConnection.java +6 −6 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.Log; import android.util.Pair; import android.view.IWindowManager; import android.view.InputDevice; import android.view.InputEvent; Loading @@ -52,7 +51,8 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; import android.window.ScreenCapture; import android.window.ScreenCapture.CaptureArgs; import android.window.ScreenCapture.ScreenCaptureListener; import android.window.ScreenCapture.ScreenshotHardwareBuffer; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import libcore.io.IoUtils; Loading Loading @@ -235,12 +235,12 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { final CaptureArgs captureArgs = new CaptureArgs.Builder<>() .setSourceCrop(crop) .build(); Pair<ScreenCaptureListener, ScreenCapture.ScreenshotSync> syncScreenCapture = SynchronousScreenCaptureListener syncScreenCapture = ScreenCapture.createSyncCaptureListener(); mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs, syncScreenCapture.first); final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.second.get(); syncScreenCapture); final ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.getBuffer(); return screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); } catch (RemoteException re) { re.rethrowAsRuntimeException(); Loading core/java/android/window/ScreenCapture.java +38 −31 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import android.util.Pair; import android.view.SurfaceControl; import libcore.util.NativeAllocationRegistry; Loading Loading @@ -73,14 +72,14 @@ public class ScreenCapture { */ public static ScreenshotHardwareBuffer captureDisplay( DisplayCaptureArgs captureArgs) { Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener(); int status = captureDisplay(captureArgs, syncScreenCapture.first); SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener(); int status = captureDisplay(captureArgs, syncScreenCapture); if (status != 0) { return null; } try { return syncScreenCapture.second.get(); return syncScreenCapture.getBuffer(); } catch (Exception e) { return null; } Loading Loading @@ -133,14 +132,14 @@ public class ScreenCapture { * @hide */ public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) { Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener(); int status = captureLayers(captureArgs, syncScreenCapture.first); SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener(); int status = captureLayers(captureArgs, syncScreenCapture); if (status != 0) { return null; } try { return syncScreenCapture.second.get(); return syncScreenCapture.getBuffer(); } catch (Exception e) { return null; } Loading Loading @@ -743,14 +742,35 @@ public class ScreenCapture { * A helper method to handle the async screencapture callbacks synchronously. This should only * be used if the screencapture caller doesn't care that it blocks waiting for a screenshot. * * @return a Pair that holds the {@link ScreenCaptureListener} that should be used for capture * calls into SurfaceFlinger and a {@link ScreenshotSync} object to retrieve the results. */ public static Pair<ScreenCaptureListener, ScreenshotSync> createSyncCaptureListener() { final ScreenshotSync screenshotSync = new ScreenshotSync(); final ScreenCaptureListener screenCaptureListener = new ScreenCaptureListener( screenshotSync::setScreenshotHardwareBuffer); return new Pair<>(screenCaptureListener, screenshotSync); * @return a {@link SynchronousScreenCaptureListener} that should be used for capture * calls into SurfaceFlinger. */ public static SynchronousScreenCaptureListener createSyncCaptureListener() { ScreenshotHardwareBuffer[] bufferRef = new ScreenshotHardwareBuffer[1]; CountDownLatch latch = new CountDownLatch(1); Consumer<ScreenshotHardwareBuffer> consumer = buffer -> { bufferRef[0] = buffer; latch.countDown(); }; return new SynchronousScreenCaptureListener(consumer) { // In order to avoid requiring two GC cycles to clean up the consumer and the buffer // it references, the underlying JNI listener holds a weak reference to the consumer. // This property exists to ensure the consumer stays alive during the listener's // lifetime. private Consumer<ScreenshotHardwareBuffer> mConsumer = consumer; @Override public ScreenshotHardwareBuffer getBuffer() { try { latch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS); return bufferRef[0]; } catch (Exception e) { Log.e(TAG, "Failed to wait for screen capture result", e); return null; } } }; } /** Loading @@ -758,28 +778,15 @@ public class ScreenCapture { * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} or * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} */ public static class ScreenshotSync { private final CountDownLatch mCountDownLatch = new CountDownLatch(1); private ScreenshotHardwareBuffer mScreenshotHardwareBuffer; private void setScreenshotHardwareBuffer( ScreenshotHardwareBuffer screenshotHardwareBuffer) { mScreenshotHardwareBuffer = screenshotHardwareBuffer; mCountDownLatch.countDown(); public abstract static class SynchronousScreenCaptureListener extends ScreenCaptureListener { SynchronousScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) { super(consumer); } /** * Get the {@link ScreenshotHardwareBuffer} synchronously. This can be null if the * screenshot failed or if there was no callback in {@link #SCREENSHOT_WAIT_TIME_S} seconds. */ public ScreenshotHardwareBuffer get() { try { mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS); return mScreenshotHardwareBuffer; } catch (Exception e) { Log.e(TAG, "Failed to wait for screen capture result", e); return null; } } public abstract ScreenshotHardwareBuffer getBuffer(); } } core/jni/android_window_ScreenCapture.cpp +14 −8 Original line number Diff line number Diff line Loading @@ -81,22 +81,28 @@ class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener { public: explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) { env->GetJavaVM(&mVm); mConsumerObject = env->NewGlobalRef(jobject); LOG_ALWAYS_FATAL_IF(!mConsumerObject, "Failed to make global ref"); mConsumerWeak = env->NewWeakGlobalRef(jobject); } ~ScreenCaptureListenerWrapper() { if (mConsumerObject) { getenv()->DeleteGlobalRef(mConsumerObject); mConsumerObject = nullptr; if (mConsumerWeak) { getenv()->DeleteWeakGlobalRef(mConsumerWeak); mConsumerWeak = nullptr; } } binder::Status onScreenCaptureCompleted( const gui::ScreenCaptureResults& captureResults) override { JNIEnv* env = getenv(); ScopedLocalRef<jobject> consumer{env, env->NewLocalRef(mConsumerWeak)}; if (consumer == nullptr) { ALOGE("ScreenCaptureListenerWrapper consumer not alive."); return binder::Status::ok(); } if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) { env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, nullptr); env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, nullptr); checkAndClearException(env, "accept"); return binder::Status::ok(); } Loading @@ -111,7 +117,7 @@ public: captureResults.capturedSecureLayers, captureResults.capturedHdrLayers); checkAndClearException(env, "builder"); env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, screenshotHardwareBuffer); env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, screenshotHardwareBuffer); checkAndClearException(env, "accept"); env->DeleteLocalRef(jhardwareBuffer); env->DeleteLocalRef(screenshotHardwareBuffer); Loading @@ -119,7 +125,7 @@ public: } private: jobject mConsumerObject; jweak mConsumerWeak; JavaVM* mVm; JNIEnv* getenv() { Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +8 −8 Original line number Diff line number Diff line Loading @@ -80,8 +80,7 @@ import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager; import android.window.ScreenCapture; import android.window.ScreenCapture.ScreenCaptureListener; import android.window.ScreenCapture.ScreenshotSync; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import androidx.annotation.MainThread; import androidx.annotation.Nullable; Loading Loading @@ -1222,10 +1221,11 @@ public class BubbleController implements ConfigurationChangeListener, /** * Performs a screenshot that may exclude the bubble layer, if one is present. The screenshot * can be access via the supplied {@link ScreenshotSync#get()} asynchronously. * can be access via the supplied {@link SynchronousScreenCaptureListener#getBuffer()} * asynchronously. */ public void getScreenshotExcludingBubble(int displayId, Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener) { SynchronousScreenCaptureListener screenCaptureListener) { try { ScreenCapture.CaptureArgs args = null; if (mStackView != null) { Loading @@ -1240,7 +1240,7 @@ public class BubbleController implements ConfigurationChangeListener, } } mWmService.captureDisplay(displayId, args, screenCaptureListener.first); mWmService.captureDisplay(displayId, args, screenCaptureListener); } catch (RemoteException e) { Log.e(TAG, "Failed to capture screenshot"); } Loading Loading @@ -2211,15 +2211,15 @@ public class BubbleController implements ConfigurationChangeListener, @Override @Nullable public ScreenshotSync getScreenshotExcludingBubble(int displayId) { Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener = public SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId) { SynchronousScreenCaptureListener screenCaptureListener = ScreenCapture.createSyncCaptureListener(); mMainExecutor.execute( () -> BubbleController.this.getScreenshotExcludingBubble(displayId, screenCaptureListener)); return screenCaptureListener.second; return screenCaptureListener; } @Override Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +8 −8 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.wm.shell.bubbles; import static android.window.ScreenCapture.ScreenshotSync; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.PARAMETER; Loading @@ -34,6 +32,7 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.util.Pair; import android.util.SparseArray; import android.window.ScreenCapture.ScreenshotHardwareBuffer; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import androidx.annotation.IntDef; import androidx.annotation.Nullable; Loading Loading @@ -150,13 +149,14 @@ public interface Bubbles { boolean isAppBubbleTaskId(int taskId); /** * @return a {@link ScreenshotSync} after performing a screenshot that may exclude the bubble * layer, if one is present. The underlying {@link ScreenshotHardwareBuffer} can be access via * {@link ScreenshotSync#get()} asynchronously and care should be taken to * {@link HardwareBuffer#close()} the associated * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required. ` * @return a {@link SynchronousScreenCaptureListener} after performing a screenshot that may * exclude the bubble layer, if one is present. The underlying * {@link ScreenshotHardwareBuffer} can be accessed via * {@link SynchronousScreenCaptureListener#getBuffer()} asynchronously and care should be taken * to {@link HardwareBuffer#close()} the associated * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required.` */ ScreenshotSync getScreenshotExcludingBubble(int displayId); SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId); /** * @return a bubble that matches the provided shortcutId, if one exists. Loading Loading
core/java/android/app/UiAutomationConnection.java +6 −6 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.Log; import android.util.Pair; import android.view.IWindowManager; import android.view.InputDevice; import android.view.InputEvent; Loading @@ -52,7 +51,8 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; import android.window.ScreenCapture; import android.window.ScreenCapture.CaptureArgs; import android.window.ScreenCapture.ScreenCaptureListener; import android.window.ScreenCapture.ScreenshotHardwareBuffer; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import libcore.io.IoUtils; Loading Loading @@ -235,12 +235,12 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { final CaptureArgs captureArgs = new CaptureArgs.Builder<>() .setSourceCrop(crop) .build(); Pair<ScreenCaptureListener, ScreenCapture.ScreenshotSync> syncScreenCapture = SynchronousScreenCaptureListener syncScreenCapture = ScreenCapture.createSyncCaptureListener(); mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs, syncScreenCapture.first); final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.second.get(); syncScreenCapture); final ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.getBuffer(); return screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); } catch (RemoteException re) { re.rethrowAsRuntimeException(); Loading
core/java/android/window/ScreenCapture.java +38 −31 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import android.util.Pair; import android.view.SurfaceControl; import libcore.util.NativeAllocationRegistry; Loading Loading @@ -73,14 +72,14 @@ public class ScreenCapture { */ public static ScreenshotHardwareBuffer captureDisplay( DisplayCaptureArgs captureArgs) { Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener(); int status = captureDisplay(captureArgs, syncScreenCapture.first); SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener(); int status = captureDisplay(captureArgs, syncScreenCapture); if (status != 0) { return null; } try { return syncScreenCapture.second.get(); return syncScreenCapture.getBuffer(); } catch (Exception e) { return null; } Loading Loading @@ -133,14 +132,14 @@ public class ScreenCapture { * @hide */ public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) { Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener(); int status = captureLayers(captureArgs, syncScreenCapture.first); SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener(); int status = captureLayers(captureArgs, syncScreenCapture); if (status != 0) { return null; } try { return syncScreenCapture.second.get(); return syncScreenCapture.getBuffer(); } catch (Exception e) { return null; } Loading Loading @@ -743,14 +742,35 @@ public class ScreenCapture { * A helper method to handle the async screencapture callbacks synchronously. This should only * be used if the screencapture caller doesn't care that it blocks waiting for a screenshot. * * @return a Pair that holds the {@link ScreenCaptureListener} that should be used for capture * calls into SurfaceFlinger and a {@link ScreenshotSync} object to retrieve the results. */ public static Pair<ScreenCaptureListener, ScreenshotSync> createSyncCaptureListener() { final ScreenshotSync screenshotSync = new ScreenshotSync(); final ScreenCaptureListener screenCaptureListener = new ScreenCaptureListener( screenshotSync::setScreenshotHardwareBuffer); return new Pair<>(screenCaptureListener, screenshotSync); * @return a {@link SynchronousScreenCaptureListener} that should be used for capture * calls into SurfaceFlinger. */ public static SynchronousScreenCaptureListener createSyncCaptureListener() { ScreenshotHardwareBuffer[] bufferRef = new ScreenshotHardwareBuffer[1]; CountDownLatch latch = new CountDownLatch(1); Consumer<ScreenshotHardwareBuffer> consumer = buffer -> { bufferRef[0] = buffer; latch.countDown(); }; return new SynchronousScreenCaptureListener(consumer) { // In order to avoid requiring two GC cycles to clean up the consumer and the buffer // it references, the underlying JNI listener holds a weak reference to the consumer. // This property exists to ensure the consumer stays alive during the listener's // lifetime. private Consumer<ScreenshotHardwareBuffer> mConsumer = consumer; @Override public ScreenshotHardwareBuffer getBuffer() { try { latch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS); return bufferRef[0]; } catch (Exception e) { Log.e(TAG, "Failed to wait for screen capture result", e); return null; } } }; } /** Loading @@ -758,28 +778,15 @@ public class ScreenCapture { * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} or * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} */ public static class ScreenshotSync { private final CountDownLatch mCountDownLatch = new CountDownLatch(1); private ScreenshotHardwareBuffer mScreenshotHardwareBuffer; private void setScreenshotHardwareBuffer( ScreenshotHardwareBuffer screenshotHardwareBuffer) { mScreenshotHardwareBuffer = screenshotHardwareBuffer; mCountDownLatch.countDown(); public abstract static class SynchronousScreenCaptureListener extends ScreenCaptureListener { SynchronousScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) { super(consumer); } /** * Get the {@link ScreenshotHardwareBuffer} synchronously. This can be null if the * screenshot failed or if there was no callback in {@link #SCREENSHOT_WAIT_TIME_S} seconds. */ public ScreenshotHardwareBuffer get() { try { mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS); return mScreenshotHardwareBuffer; } catch (Exception e) { Log.e(TAG, "Failed to wait for screen capture result", e); return null; } } public abstract ScreenshotHardwareBuffer getBuffer(); } }
core/jni/android_window_ScreenCapture.cpp +14 −8 Original line number Diff line number Diff line Loading @@ -81,22 +81,28 @@ class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener { public: explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) { env->GetJavaVM(&mVm); mConsumerObject = env->NewGlobalRef(jobject); LOG_ALWAYS_FATAL_IF(!mConsumerObject, "Failed to make global ref"); mConsumerWeak = env->NewWeakGlobalRef(jobject); } ~ScreenCaptureListenerWrapper() { if (mConsumerObject) { getenv()->DeleteGlobalRef(mConsumerObject); mConsumerObject = nullptr; if (mConsumerWeak) { getenv()->DeleteWeakGlobalRef(mConsumerWeak); mConsumerWeak = nullptr; } } binder::Status onScreenCaptureCompleted( const gui::ScreenCaptureResults& captureResults) override { JNIEnv* env = getenv(); ScopedLocalRef<jobject> consumer{env, env->NewLocalRef(mConsumerWeak)}; if (consumer == nullptr) { ALOGE("ScreenCaptureListenerWrapper consumer not alive."); return binder::Status::ok(); } if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) { env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, nullptr); env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, nullptr); checkAndClearException(env, "accept"); return binder::Status::ok(); } Loading @@ -111,7 +117,7 @@ public: captureResults.capturedSecureLayers, captureResults.capturedHdrLayers); checkAndClearException(env, "builder"); env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, screenshotHardwareBuffer); env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, screenshotHardwareBuffer); checkAndClearException(env, "accept"); env->DeleteLocalRef(jhardwareBuffer); env->DeleteLocalRef(screenshotHardwareBuffer); Loading @@ -119,7 +125,7 @@ public: } private: jobject mConsumerObject; jweak mConsumerWeak; JavaVM* mVm; JNIEnv* getenv() { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +8 −8 Original line number Diff line number Diff line Loading @@ -80,8 +80,7 @@ import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager; import android.window.ScreenCapture; import android.window.ScreenCapture.ScreenCaptureListener; import android.window.ScreenCapture.ScreenshotSync; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import androidx.annotation.MainThread; import androidx.annotation.Nullable; Loading Loading @@ -1222,10 +1221,11 @@ public class BubbleController implements ConfigurationChangeListener, /** * Performs a screenshot that may exclude the bubble layer, if one is present. The screenshot * can be access via the supplied {@link ScreenshotSync#get()} asynchronously. * can be access via the supplied {@link SynchronousScreenCaptureListener#getBuffer()} * asynchronously. */ public void getScreenshotExcludingBubble(int displayId, Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener) { SynchronousScreenCaptureListener screenCaptureListener) { try { ScreenCapture.CaptureArgs args = null; if (mStackView != null) { Loading @@ -1240,7 +1240,7 @@ public class BubbleController implements ConfigurationChangeListener, } } mWmService.captureDisplay(displayId, args, screenCaptureListener.first); mWmService.captureDisplay(displayId, args, screenCaptureListener); } catch (RemoteException e) { Log.e(TAG, "Failed to capture screenshot"); } Loading Loading @@ -2211,15 +2211,15 @@ public class BubbleController implements ConfigurationChangeListener, @Override @Nullable public ScreenshotSync getScreenshotExcludingBubble(int displayId) { Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener = public SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId) { SynchronousScreenCaptureListener screenCaptureListener = ScreenCapture.createSyncCaptureListener(); mMainExecutor.execute( () -> BubbleController.this.getScreenshotExcludingBubble(displayId, screenCaptureListener)); return screenCaptureListener.second; return screenCaptureListener; } @Override Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +8 −8 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.wm.shell.bubbles; import static android.window.ScreenCapture.ScreenshotSync; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.PARAMETER; Loading @@ -34,6 +32,7 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.util.Pair; import android.util.SparseArray; import android.window.ScreenCapture.ScreenshotHardwareBuffer; import android.window.ScreenCapture.SynchronousScreenCaptureListener; import androidx.annotation.IntDef; import androidx.annotation.Nullable; Loading Loading @@ -150,13 +149,14 @@ public interface Bubbles { boolean isAppBubbleTaskId(int taskId); /** * @return a {@link ScreenshotSync} after performing a screenshot that may exclude the bubble * layer, if one is present. The underlying {@link ScreenshotHardwareBuffer} can be access via * {@link ScreenshotSync#get()} asynchronously and care should be taken to * {@link HardwareBuffer#close()} the associated * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required. ` * @return a {@link SynchronousScreenCaptureListener} after performing a screenshot that may * exclude the bubble layer, if one is present. The underlying * {@link ScreenshotHardwareBuffer} can be accessed via * {@link SynchronousScreenCaptureListener#getBuffer()} asynchronously and care should be taken * to {@link HardwareBuffer#close()} the associated * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required.` */ ScreenshotSync getScreenshotExcludingBubble(int displayId); SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId); /** * @return a bubble that matches the provided shortcutId, if one exists. Loading