Skip to content

Commit

Permalink
Add retrieveBugreport() to ShadowBugreportManager, which was added
Browse files Browse the repository at this point in the history
in Android U.

Like startBugreport(), a bug report cannot be retrieved if another one is
currently being generated.

PiperOrigin-RevId: 577243040
  • Loading branch information
Googler authored and Copybara-Service committed Oct 27, 2023
1 parent f733a0a commit 258c977
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 1 deletion.
@@ -1,6 +1,7 @@
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertThrows;
Expand Down Expand Up @@ -62,6 +63,18 @@ public void requestBugreport() {
assertThat(shadowBugreportManager.getShareDescription().toString()).isEqualTo(description);
}

@Test
public void requestBugreport_resetDoesNotCrash() {
String title = "title";
String description = "description";
shadowBugreportManager.requestBugreport(
new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE), title, description);

// executeOnFInished() will call resetParams(), which should not crash from referencing any null
// values.
shadowBugreportManager.executeOnFinished();
}

@Test
public void startBugreport() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
Expand Down Expand Up @@ -137,6 +150,38 @@ public void startTwoBugreports() throws Exception {
verify(callback, never()).onError(anyInt());
}

@Test
@Config(minSdk = UPSIDE_DOWN_CAKE)
public void retrieveBugreport() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
shadowBugreportManager.retrieveBugreport(
"bugreportFile", createWriteFile("bugreport"), directExecutor(), callback);
shadowMainLooper().idle();

assertThat(shadowBugreportManager.isBugreportInProgress()).isTrue();
assertThat(shadowBugreportManager.getBugreportFd()).isNotNull();
assertThat(shadowBugreportManager.getScreenshotFd()).isNull();
verify(callback, never()).onFinished();
verify(callback, never()).onError(anyInt());
}

@Test
@Config(minSdk = UPSIDE_DOWN_CAKE)
public void retrieveBugreport_noPermission() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
shadowBugreportManager.setHasPermission(false);

assertThrows(
SecurityException.class,
() ->
shadowBugreportManager.retrieveBugreport(
"bugreportFile", createWriteFile("bugreport"), directExecutor(), callback));
shadowMainLooper().idle();

assertThat(shadowBugreportManager.isBugreportInProgress()).isFalse();
verifyNoMoreInteractions(callback);
}

@Test
public void cancelBugreport() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
Expand Down Expand Up @@ -229,6 +274,41 @@ public void executeOnFinished() throws Exception {
assertThat(shadowBugreportManager.getScreenshotFd()).isNull();
}

@Test
@Config(minSdk = UPSIDE_DOWN_CAKE)
public void executeOnFinishedWithString() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
shadowBugreportManager.retrieveBugreport(
"bugreportFile", createWriteFile("bugreport"), directExecutor(), callback);
shadowMainLooper().idle();

shadowBugreportManager.executeOnFinished("bugreportFile");
shadowMainLooper().idle();

assertThat(shadowBugreportManager.isBugreportInProgress()).isFalse();
verify(callback).onFinished("bugreportFile");
verify(callback, never()).onError(anyInt());
assertThat(shadowBugreportManager.getBugreportFd()).isNull();
}

@Test
@Config(minSdk = UPSIDE_DOWN_CAKE)
public void executeOnFinishedWithString_bugreportInProgress() throws Exception {
BugreportCallback callback = mock(BugreportCallback.class);
shadowBugreportManager.retrieveBugreport(
"bugreportFile", createWriteFile("bugreport"), directExecutor(), callback);
shadowMainLooper().idle();

assertThat(shadowBugreportManager.isBugreportInProgress()).isTrue();
verify(callback, never()).onError(anyInt());

shadowBugreportManager.retrieveBugreport(
"bugreportFile", createWriteFile("bugreport"), directExecutor(), callback);
shadowMainLooper().idle();

verify(callback).onError(BugreportCallback.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
}

@Test
public void executeOnProgress() throws Exception {
// Not reported without a callback attached.
Expand Down
Expand Up @@ -2,6 +2,7 @@

import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;

import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
Expand Down Expand Up @@ -70,6 +71,23 @@ protected void requestBugreport(
this.shareDescription = shareDescription;
}

@Implementation(minSdk = UPSIDE_DOWN_CAKE)
protected void retrieveBugreport(
String bugreportFile,
ParcelFileDescriptor bugreportFd,
Executor executor,
BugreportCallback callback) {
enforcePermission("retrieveBugreport");
if (isBugreportInProgress()) {
executor.execute(
() -> callback.onError(BugreportCallback.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS));
} else {
this.bugreportFd = bugreportFd;
this.executor = executor;
this.callback = callback;
}
}

/** Cancels bugreport in progress and executes {@link BugreportCallback#onError}. */
@Implementation
protected void cancelBugreport() {
Expand Down Expand Up @@ -103,6 +121,15 @@ public void executeOnFinished() {
resetParams();
}

/** Executes {@link BugreportCallback#onFinished(String)} on the provided Executor. */
public void executeOnFinished(String bugreportFile) {
if (isBugreportInProgress()) {
BugreportCallback callback = this.callback;
executor.execute(() -> callback.onFinished(bugreportFile));
}
resetParams();
}

public boolean isBugreportInProgress() {
return executor != null && callback != null;
}
Expand Down Expand Up @@ -140,6 +167,15 @@ public CharSequence getShareDescription() {
return shareDescription;
}

/**
* Returns the bug report file descriptor if set with {@code startBugreport} or {@code
* retrieveBugreport}, else null.
*/
@Nullable
public ParcelFileDescriptor getBugreportFd() {
return bugreportFd;
}

/** Returns the screenshot file descriptor if set with {@code startBugreport}, else null. */
@Nullable
public ParcelFileDescriptor getScreenshotFd() {
Expand All @@ -148,7 +184,9 @@ public ParcelFileDescriptor getScreenshotFd() {

private void resetParams() {
try {
bugreportFd.close();
if (bugreportFd != null) {
bugreportFd.close();
}
if (screenshotFd != null) {
screenshotFd.close();
}
Expand Down

0 comments on commit 258c977

Please sign in to comment.