Skip to content

Commit f3182f5

Browse files
brettchabotcopybara-androidxtest
authored andcommitted
Promote captureToBitmap and related APIs to stable
PiperOrigin-RevId: 628167988
1 parent 3a23fe9 commit f3182f5

File tree

11 files changed

+58
-28
lines changed

11 files changed

+58
-28
lines changed

core/CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
**API Changes**
1616

1717
* Added ApplicationInfoBuilder.setFlags(int)
18-
* Make suspend function versions of ViewCapture/WindowCapture/DeviceCapture APIs
18+
* Make suspend function versions of ViewCapture/WindowCapture/DeviceCapture APIs,
19+
and rename existing methods as *Async variants that return ListenableFutures
1920
* Make Bitmap.writeToTestStorage use the registered PlatformTestStorage instead of hardcoding TestStorage
20-
* Add *Async variants of capture*ToBitmap methods
21-
21+
* Remove ExperimentalTestApi/RequiresOptIn restrictions from captureToBitmap and takeScreenshot APIs
2222

2323
**Breaking API Changes**
2424

core/java/androidx/test/core/api/current_internal.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
// Signature format: 3.0
2+
package androidx.test.core.app {
3+
4+
public final class DeviceCapture {
5+
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean canTakeScreenshot();
6+
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static android.graphics.Bitmap takeScreenshotNoSync() throws java.lang.RuntimeException;
7+
}
8+
9+
}
10+
211
package androidx.test.core.graphics {
312

413
public final class BitmapStorage {
@@ -7,3 +16,11 @@ package androidx.test.core.graphics {
716

817
}
918

19+
package androidx.test.core.view {
20+
21+
public final class ViewCapture {
22+
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static suspend Object? forceRedraw(android.view.View, kotlin.coroutines.Continuation<? super kotlin.Unit>);
23+
}
24+
25+
}
26+

core/java/androidx/test/core/api/current_public.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ package androidx.test.core.app {
2626
method public static <T extends android.content.Context> T! getApplicationContext();
2727
}
2828

29+
public final class DeviceCapture {
30+
method @kotlin.jvm.Throws(exceptionClasses=RuntimeException::class) public static android.graphics.Bitmap takeScreenshot() throws java.lang.RuntimeException;
31+
}
32+
2933
}
3034

3135
package androidx.test.core.content.pm {
@@ -53,6 +57,7 @@ package androidx.test.core.content.pm {
5357
package androidx.test.core.graphics {
5458

5559
public final class BitmapStorage {
60+
method @kotlin.jvm.Throws(exceptionClasses=IOException::class) public static void writeToTestStorage(android.graphics.Bitmap, String name) throws java.io.IOException;
5661
}
5762

5863
}
@@ -104,5 +109,15 @@ package androidx.test.core.view {
104109
method public androidx.test.core.view.PointerPropertiesBuilder! setToolType(int);
105110
}
106111

112+
public final class ViewCapture {
113+
method public static suspend Object? captureToBitmap(android.view.View, android.graphics.Rect? rect = null, kotlin.coroutines.Continuation<? super android.graphics.Bitmap>);
114+
method public static com.google.common.util.concurrent.ListenableFuture<android.graphics.Bitmap> captureToBitmapAsync(android.view.View, android.graphics.Rect? rect = null);
115+
}
116+
117+
public final class WindowCapture {
118+
method public static suspend Object? captureRegionToBitmap(android.view.Window, android.graphics.Rect? boundsInWindow = null, kotlin.coroutines.Continuation<? super android.graphics.Bitmap>);
119+
method public static com.google.common.util.concurrent.ListenableFuture<android.graphics.Bitmap> captureRegionToBitmapAsync(android.view.Window, android.graphics.Rect? boundsInWindow = null);
120+
}
121+
107122
}
108123

core/java/androidx/test/core/app/DeviceCapture.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import android.os.Looper
2424
import android.util.Log
2525
import android.view.Choreographer
2626
import androidx.annotation.RestrictTo
27-
import androidx.test.annotation.ExperimentalTestApi
2827
import androidx.test.core.internal.os.HandlerExecutor
2928
import androidx.test.core.view.forceRedraw
3029
import androidx.test.internal.util.Checks
@@ -46,8 +45,10 @@ import kotlinx.coroutines.withTimeout
4645
* this method returns false then attempting to take a screenshot will fail. Note that taking a
4746
* screenshot may still fail if this method returns true, for example if the call to [UiAutomation]
4847
* fails.
48+
*
49+
* @hide
4950
*/
50-
@ExperimentalTestApi
51+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
5152
fun canTakeScreenshot(): Boolean =
5253
getInstrumentation().uiAutomation != null && Looper.myLooper() != Looper.getMainLooper()
5354

@@ -72,7 +73,6 @@ fun canTakeScreenshot(): Boolean =
7273
* @throws [IllegalStateException] if called on the main thread. This is a limitation of connecting
7374
* to UiAutomation, [RuntimeException] if UiAutomation fails to take the screenshot
7475
*/
75-
@ExperimentalTestApi
7676
@Suppress("FutureReturnValueIgnored")
7777
@Throws(RuntimeException::class)
7878
fun takeScreenshot(): Bitmap {
@@ -91,7 +91,6 @@ fun takeScreenshot(): Bitmap {
9191
* to UiAutomation, [RuntimeException] if UiAutomation fails to take the screenshot
9292
* @hide
9393
*/
94-
@ExperimentalTestApi
9594
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
9695
@Suppress("FutureReturnValueIgnored")
9796
@Throws(RuntimeException::class)

core/java/androidx/test/core/graphics/BitmapStorageExt.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package androidx.test.core.graphics
2020

2121
import android.graphics.Bitmap
2222
import androidx.annotation.RestrictTo
23-
import androidx.test.annotation.ExperimentalTestApi
2423
import androidx.test.platform.io.PlatformTestStorage
2524
import androidx.test.platform.io.PlatformTestStorageRegistry
2625
import java.io.IOException
@@ -31,7 +30,6 @@ import java.io.IOException
3130
* @param name a descriptive base name for the resulting file. '.png' will be appended to this name.
3231
* @throws IOException if bitmap could not be compressed or written to ds
3332
*/
34-
@ExperimentalTestApi
3533
@Throws(IOException::class)
3634
fun Bitmap.writeToTestStorage(name: String) {
3735
writeToTestStorage(PlatformTestStorageRegistry.getInstance(), name)

core/java/androidx/test/core/view/ViewCapture.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import android.view.View
3232
import android.view.ViewTreeObserver.OnDrawListener
3333
import android.view.WindowManager
3434
import androidx.annotation.RequiresApi
35+
import androidx.annotation.RestrictTo
3536
import androidx.concurrent.futures.SuspendToFutureAdapter
36-
import androidx.test.annotation.ExperimentalTestApi
3737
import androidx.test.core.internal.os.HandlerExecutor
3838
import androidx.test.internal.platform.ServiceLoaderWrapper
3939
import androidx.test.internal.platform.os.ControlledLooper
@@ -79,10 +79,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
7979
* The resulting image is captured after forcing the View to redraw, and waiting for the draw to
8080
* operation complete. This is done as a means to improve the stability of the resulting image -
8181
* especially in cases where hardware rendering drawing is off initially.
82-
*
83-
* This API is currently experimental and subject to change or removal.
8482
*/
85-
@ExperimentalTestApi
8683
suspend fun View.captureToBitmap(rect: Rect? = null): Bitmap {
8784
checkState(isAttachedToWindow, "View must be attached to a window")
8885
checkState(
@@ -110,7 +107,6 @@ private fun getControlledLooper(): ControlledLooper {
110107
}
111108

112109
/** A ListenableFuture variant of captureToBitmap intended for use from Java. */
113-
@ExperimentalTestApi
114110
fun View.captureToBitmapAsync(rect: Rect? = null): ListenableFuture<Bitmap> {
115111
return SuspendToFutureAdapter.launchFuture(Dispatchers.Main) { captureToBitmap(rect) }
116112
}
@@ -119,10 +115,10 @@ fun View.captureToBitmapAsync(rect: Rect? = null): ListenableFuture<Bitmap> {
119115
* Trigger a redraw of the given view.
120116
*
121117
* Should only be called on UI thread.
118+
*
119+
* @hide
122120
*/
123-
// TODO(b/316921934): uncomment once @ExperimentalTestApi is removed
124-
// @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
125-
@ExperimentalTestApi
121+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
126122
suspend fun View.forceRedraw() {
127123
checkState(handler.looper.isCurrentThread, "Must be called from view's handler thread")
128124
if (!getControlledLooper().areDrawCallbacksSupported()) {

core/java/androidx/test/core/view/WindowCapture.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import android.view.PixelCopy
2626
import android.view.Window
2727
import androidx.annotation.RequiresApi
2828
import androidx.concurrent.futures.SuspendToFutureAdapter
29-
import androidx.test.annotation.ExperimentalTestApi
3029
import androidx.test.platform.graphics.HardwareRendererCompat
3130
import com.google.common.util.concurrent.ListenableFuture
3231
import kotlin.coroutines.resumeWithException
@@ -49,10 +48,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
4948
* The resulting image is captured after forcing the View to redraw, and waiting for the draw to
5049
* operation complete. This is done as a means to improve the stability of the resulting image -
5150
* especially in cases where hardware rendering drawing is off initially.
52-
*
53-
* This API is currently experimental and subject to change or removal.
5451
*/
55-
@ExperimentalTestApi
5652
suspend fun Window.captureRegionToBitmap(boundsInWindow: Rect? = null): Bitmap {
5753
var bitmap: Bitmap? = null
5854

@@ -69,7 +65,6 @@ suspend fun Window.captureRegionToBitmap(boundsInWindow: Rect? = null): Bitmap {
6965
}
7066

7167
/** A ListenableFuture variant of captureRegionToBitmap intended for use from Java. */
72-
@ExperimentalTestApi
7368
fun Window.captureRegionToBitmapAsync(boundsInWindow: Rect? = null): ListenableFuture<Bitmap> {
7469
return SuspendToFutureAdapter.launchFuture(Dispatchers.Main) {
7570
captureRegionToBitmap(boundsInWindow)

espresso/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ The following artifacts were released:
2929
**API Changes**
3030

3131
* Adapt to ViewCapture API changes
32-
* Delete ViewInteraction.captureToBitmap in favor of ViewActions.captureToBitmap
32+
* Delete ViewInteraction.captureToBitmap in favor of ViewActions.captureToBitmap,
33+
and promote to a stable API from ExperimentalTestApi
3334

3435

3536
**Breaking API Changes**

espresso/core/java/androidx/test/espresso/action/CaptureToBitmapAction.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package androidx.test.espresso.action
33
import android.os.Handler
44
import android.os.Looper
55
import android.view.View
6-
import androidx.test.annotation.ExperimentalTestApi
76
import androidx.test.core.internal.os.HandlerExecutor
87
import androidx.test.core.view.captureToBitmapAsync
98
import androidx.test.espresso.IdlingRegistry
@@ -14,7 +13,6 @@ import java.util.concurrent.TimeUnit
1413
import org.hamcrest.Matcher
1514
import org.hamcrest.Matchers.any
1615

17-
@ExperimentalTestApi
1816
class CaptureToBitmapAction(val bitmapReceiver: ViewActions.BitmapReceiver) : ViewAction {
1917
override fun getConstraints(): Matcher<View> {
2018
return any(View::class.java)

espresso/core/java/androidx/test/espresso/action/ViewActions.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import android.view.MotionEvent;
3131
import android.view.View;
3232
import androidx.annotation.NonNull;
33-
import androidx.test.annotation.ExperimentalTestApi;
3433
import androidx.test.espresso.PerformException;
3534
import androidx.test.espresso.UiController;
3635
import androidx.test.espresso.ViewAction;
@@ -571,7 +570,6 @@ public static ViewAction repeatedlyUntil(
571570
new RepeatActionUntilViewState(action, desiredStateMatcher, maxAttempts));
572571
}
573572

574-
@ExperimentalTestApi
575573
public interface BitmapReceiver {
576574
void onBitmapCaptured(Bitmap bitmap);
577575
}
@@ -585,7 +583,6 @@ public interface BitmapReceiver {
585583
* thread.
586584
* @return the ViewAction
587585
*/
588-
@ExperimentalTestApi
589586
public static ViewAction captureToBitmap(BitmapReceiver bitmapReceiver) {
590587
return new CaptureToBitmapAction(bitmapReceiver);
591588
}

0 commit comments

Comments
 (0)