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

Allow IntentStubberRegistry to be called from any thread. #2327

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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: 2 additions & 0 deletions runner/monitor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
`androidx.test:monitor:{version}` is released.

**Bug Fixes**
* Activities can be started from any thread.

**New Features**

Expand All @@ -14,6 +15,7 @@

* Update to minSdkVersion 21
* Make ReflectionException a RuntimeException
* Hid IntentStubberRegistry.getInstance()

**Breaking API Changes**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ private static class StubResultCallable implements Callable<ActivityResult> {

@Override
public ActivityResult call() {
return IntentStubberRegistry.getInstance().getActivityResultForIntent(intent);
return IntentStubberRegistry.getActivityResultForIntent(intent);
}
}

Expand Down Expand Up @@ -707,7 +707,7 @@ private ActivityResult stubResultFor(Intent intent) {
throw new RuntimeException(e);
}
} else {
return IntentStubberRegistry.getInstance().getActivityResultForIntent(intent);
return IntentStubberRegistry.getActivityResultForIntent(intent);
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
import static androidx.test.internal.util.Checks.checkNotNull;
import static androidx.test.internal.util.Checks.checkState;

import android.os.Looper;
import android.app.Instrumentation.ActivityResult;
import android.content.Intent;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/** Exposes an implementation of {@link IntentStubber}. */
public final class IntentStubberRegistry {

private static IntentStubber instance;
private static final AtomicReference<IntentStubber> instance = new AtomicReference<>();

private static AtomicBoolean isLoaded = new AtomicBoolean();
private static final AtomicBoolean isLoaded = new AtomicBoolean();

/**
* Loads an {@link IntentStubber} into this registry. There can only be one active stubber at a
Expand All @@ -37,44 +39,51 @@ public final class IntentStubberRegistry {
*
* <p>This method can be called from any thread.
*/
public static void load(IntentStubber intentStubber) {
public static synchronized void load(IntentStubber intentStubber) {
checkNotNull(intentStubber, "IntentStubber cannot be null!");
checkState(
!isLoaded.getAndSet(true),
"Intent stubber already registered! Multiple stubbers are not"
+ "allowedAre you running under an ");
instance = intentStubber;
instance.set(intentStubber);
}

/** @return if an {@link IntentStubber} has been loaded. */
/** Returns if an {@link IntentStubber} has been loaded. */
public static boolean isLoaded() {
return isLoaded.get();
}

/** Clears the current instance of Intent Stubber. */
public static synchronized void reset() {
instance.set(null);
isLoaded.set(false);
}

/**
* Returns the activity result for the given intent..
*
* <p>This method can be called from any thread.
*
* @throws IllegalStateException if no Intent Stubber has been loaded.
*/
public static ActivityResult getActivityResultForIntent(Intent intent) {
return getInstance().getActivityResultForIntent(intent);
}

/**
* Returns the loaded Intent Stubber instance.
*
* @throws IllegalStateException if this method is not called on the main thread.
* <p>This method can be called from any thread.
*
* @throws IllegalStateException if no Intent Stubber has been loaded.
*/
public static IntentStubber getInstance() {
checkMain();
checkState(
null != instance,
private static IntentStubber getInstance() {
checkNotNull(
instance,
"No intent monitor registered! Are you running under an "
+ "Instrumentation which registers intent monitors?");
return instance;
}

private static void checkMain() {
checkState(Looper.myLooper() == Looper.getMainLooper(), "Must be called on main thread.");
return instance.get();
}

private IntentStubberRegistry() {}

/** Clears the current instance of Intent Stubber. */
public static synchronized void reset() {
instance = null;
isLoaded.set(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ public void tearDown() throws Exception {
public void testIntentStubberLoading() {
IntentStubberRegistry.load(mIntentStubber);
assertThat(IntentStubberRegistry.isLoaded()).isTrue();

assertThat(IntentStubberRegistry.getInstance()).isNotNull();
}

@Test
Expand All @@ -83,22 +81,17 @@ public void testLoadPassingNullThrows() {
}

@Test
public void testGetInstanceCanOnlyBeCalledOnMainThread() {
public void testGetActivityResultForIntent_loaded_returnsActivityResult() {
IntentStubberRegistry.load(mIntentStubber);
try {
IntentStubberRegistry.getInstance();
fail(
"IllegalStateException expected. getInstance() should only be allowed on main"
+ "thread!");
} catch (IllegalStateException expected) {
}

assertThat(IntentStubberRegistry.getActivityResultForIntent(new Intent())).isNotNull();
}

@Test
public void testNoInstanceLoadedThrows() {
public void testGetActivityResultForIntent_notLoaded_throws() {
try {
IntentStubberRegistry.getInstance();
fail("IllegalStateException expected. No instance available, load must be called" + "first");
IntentStubberRegistry.getActivityResultForIntent(new Intent());
fail("IllegalStateException expected. No instance available, load must be called first");
} catch (IllegalStateException expected) {
}
}
Expand Down
Loading