package org.robolectric.shadows;
import android.app.Activity;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import com.google.common.util.concurrent.SettableFuture;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.R;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.TestRunners;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static junit.framework.Assert.assertEquals;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Robolectric.buildActivity;
import static org.robolectric.Shadows.shadowOf;
@RunWith(TestRunners.MultiApiSelfTest.class)
public class ShadowContextWrapperTest {
public ArrayList<String> transcript;
private ContextWrapper contextWrapper;
@Before public void setUp() throws Exception {
transcript = new ArrayList<>();
contextWrapper = new ContextWrapper(RuntimeEnvironment.application);
}
@Test
public void registerReceiver_shouldRegisterForAllIntentFilterActions() throws Exception {
BroadcastReceiver receiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"));
contextWrapper.sendBroadcast(new Intent("foo"));
assertThat(transcript).containsExactly("Larry notified of foo");
transcript.clear();
contextWrapper.sendBroadcast(new Intent("womp"));
assertThat(transcript).isEmpty();
contextWrapper.sendBroadcast(new Intent("baz"));
assertThat(transcript).containsExactly("Larry notified of baz");
}
@Test
public void sendBroadcast_shouldSendIntentToEveryInterestedReceiver() throws Exception {
BroadcastReceiver larryReceiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(larryReceiver, intentFilter("foo", "baz"));
BroadcastReceiver bobReceiver = broadcastReceiver("Bob");
contextWrapper.registerReceiver(bobReceiver, intentFilter("foo"));
contextWrapper.sendBroadcast(new Intent("foo"));
assertThat(transcript).containsExactly("Larry notified of foo", "Bob notified of foo");
transcript.clear();
contextWrapper.sendBroadcast(new Intent("womp"));
assertThat(transcript).isEmpty();
contextWrapper.sendBroadcast(new Intent("baz"));
assertThat(transcript).containsExactly("Larry notified of baz");
}
@Test
public void sendBroadcast_shouldOnlySendIntentWithMatchingReceiverPermission() {
BroadcastReceiver receiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"), "validPermission", null);
contextWrapper.sendBroadcast(new Intent("foo"));
assertThat(transcript).isEmpty();
contextWrapper.sendBroadcast(new Intent("foo"), null);
assertThat(transcript).isEmpty();
contextWrapper.sendBroadcast(new Intent("foo"), "wrongPermission");
assertThat(transcript).isEmpty();
contextWrapper.sendBroadcast(new Intent("foo"), "validPermission");
assertThat(transcript).containsExactly("Larry notified of foo");
transcript.clear();
contextWrapper.sendBroadcast(new Intent("baz"), "validPermission");
assertThat(transcript).containsExactly("Larry notified of baz");
}
@Test
public void sendBroadcast_shouldSendIntentUsingHandlerIfOneIsProvided() {
HandlerThread handlerThread = new HandlerThread("test");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
assertNotSame(handler.getLooper(), Looper.getMainLooper());
BroadcastReceiver receiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"), null, handler);
assertThat(shadowOf(handler.getLooper()).getScheduler().size()).isEqualTo(0);
contextWrapper.sendBroadcast(new Intent("foo"));
assertThat(shadowOf(handler.getLooper()).getScheduler().size()).isEqualTo(1);
shadowOf(handlerThread.getLooper()).idle();
assertThat(shadowOf(handler.getLooper()).getScheduler().size()).isEqualTo(0);
assertThat(transcript).containsExactly("Larry notified of foo");
}
@Test
public void sendOrderedBroadcast_shouldReturnValues() throws Exception {
String action = "test";
IntentFilter lowFilter = new IntentFilter(action);
lowFilter.setPriority(1);
BroadcastReceiver lowReceiver = broadcastReceiver("Low");
contextWrapper.registerReceiver(lowReceiver, lowFilter);
IntentFilter highFilter = new IntentFilter(action);
highFilter.setPriority(2);
BroadcastReceiver highReceiver = broadcastReceiver("High");
contextWrapper.registerReceiver(highReceiver, highFilter);
final FooReceiver resultReceiver = new FooReceiver();
contextWrapper.sendOrderedBroadcast(new Intent(action), null, resultReceiver, null, 1, "initial", null);
assertThat(transcript).containsExactly("High notified of test", "Low notified of test");
assertThat(resultReceiver.resultCode).isEqualTo(1);
}
private static final class FooReceiver extends BroadcastReceiver {
private int resultCode;
private SettableFuture<Void> settableFuture = SettableFuture.create();
@Override
public void onReceive(Context context, Intent intent) {
resultCode = getResultCode();
settableFuture.set(null);
}
}
@Test
public void sendOrderedBroadcast_shouldExecuteSerially() {
String action = "test";
AtomicReference<BroadcastReceiver.PendingResult> midResult = new AtomicReference<>();
IntentFilter lowFilter = new IntentFilter(action);
lowFilter.setPriority(1);
BroadcastReceiver lowReceiver = broadcastReceiver("Low");
contextWrapper.registerReceiver(lowReceiver, lowFilter);
IntentFilter midFilter = new IntentFilter(action);
midFilter.setPriority(2);
AsyncReceiver midReceiver = new AsyncReceiver(midResult);
contextWrapper.registerReceiver(midReceiver, midFilter);
IntentFilter highFilter = new IntentFilter(action);
highFilter.setPriority(3);
BroadcastReceiver highReceiver = broadcastReceiver("High");
contextWrapper.registerReceiver(highReceiver, highFilter);
contextWrapper.sendOrderedBroadcast(new Intent(action), null);
assertThat(transcript).containsExactly("High notified of test", "Mid notified of test");
transcript.clear();
assertThat(midResult.get()).isNotNull();
midResult.get().finish();
Robolectric.flushForegroundThreadScheduler();
assertThat(transcript).containsExactly("Low notified of test");
}
private class AsyncReceiver extends BroadcastReceiver {
private final AtomicReference<PendingResult> reference;
private AsyncReceiver(AtomicReference<PendingResult> reference) {
this.reference = reference;
}
@Override
public void onReceive(Context context, Intent intent) {
reference.set(goAsync());
transcript.add("Mid notified of " + intent.getAction());
}
}
@Test
public void sendOrderedBroadcast_shouldSendByPriority() throws Exception {
String action = "test";
IntentFilter lowFilter = new IntentFilter(action);
lowFilter.setPriority(1);
BroadcastReceiver lowReceiver = broadcastReceiver("Low");
contextWrapper.registerReceiver(lowReceiver, lowFilter);
IntentFilter highFilter = new IntentFilter(action);
highFilter.setPriority(2);
BroadcastReceiver highReceiver = broadcastReceiver("High");
contextWrapper.registerReceiver(highReceiver, highFilter);
contextWrapper.sendOrderedBroadcast(new Intent(action), null);
assertThat(transcript).containsExactly("High notified of test", "Low notified of test");
}
@Test
public void orderedBroadcasts_shouldAbort() throws Exception {
String action = "test";
IntentFilter lowFilter = new IntentFilter(action);
lowFilter.setPriority(1);
BroadcastReceiver lowReceiver = broadcastReceiver("Low");
contextWrapper.registerReceiver(lowReceiver, lowFilter);
IntentFilter highFilter = new IntentFilter(action);
highFilter.setPriority(2);
BroadcastReceiver highReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
transcript.add("High" + " notified of " + intent.getAction());
abortBroadcast();
}
};
contextWrapper.registerReceiver(highReceiver, highFilter);
contextWrapper.sendOrderedBroadcast(new Intent(action), null);
assertThat(transcript).containsExactly("High notified of test");
}
@Test
public void unregisterReceiver_shouldUnregisterReceiver() throws Exception {
BroadcastReceiver receiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"));
contextWrapper.unregisterReceiver(receiver);
contextWrapper.sendBroadcast(new Intent("foo"));
assertThat(transcript).isEmpty();
}
@Test(expected = IllegalArgumentException.class)
public void unregisterReceiver_shouldThrowExceptionWhenReceiverIsNotRegistered() throws Exception {
contextWrapper.unregisterReceiver(new AppWidgetProvider());
}
@Test
public void broadcastReceivers_shouldBeSharedAcrossContextsPerApplicationContext() throws Exception {
BroadcastReceiver receiver = broadcastReceiver("Larry");
new ContextWrapper(RuntimeEnvironment.application).registerReceiver(receiver, intentFilter("foo", "baz"));
new ContextWrapper(RuntimeEnvironment.application).sendBroadcast(new Intent("foo"));
RuntimeEnvironment.application.sendBroadcast(new Intent("baz"));
assertThat(transcript).containsExactly("Larry notified of foo", "Larry notified of baz");
new ContextWrapper(RuntimeEnvironment.application).unregisterReceiver(receiver);
}
@Test
public void broadcasts_shouldBeLogged() {
Intent broadcastIntent = new Intent("foo");
contextWrapper.sendBroadcast(broadcastIntent);
List<Intent> broadcastIntents = shadowOf(contextWrapper).getBroadcastIntents();
assertTrue(broadcastIntents.size() == 1);
assertEquals(broadcastIntent, broadcastIntents.get(0));
}
@Test
public void sendStickyBroadcast_shouldDeliverIntentToAllRegisteredReceivers() {
BroadcastReceiver receiver = broadcastReceiver("Larry");
contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"));
contextWrapper.sendStickyBroadcast(new Intent("foo"));
assertThat(transcript).containsExactly("Larry notified of foo");
transcript.clear();
contextWrapper.sendStickyBroadcast(new Intent("womp"));
assertThat(transcript).isEmpty();
contextWrapper.sendStickyBroadcast(new Intent("baz"));
assertThat(transcript).containsExactly("Larry notified of baz");
}
@Test
public void sendStickyBroadcast_shouldStickSentIntent() {
contextWrapper.sendStickyBroadcast(new Intent("foo"));
assertThat(transcript).isEmpty();
BroadcastReceiver receiver = broadcastReceiver("Larry");
Intent sticker = contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"));
assertThat(transcript).containsExactly("Larry notified of foo");
assertThat(sticker).isNotNull();
assertThat(sticker.getAction()).isEqualTo("foo");
}
@Test
public void afterSendStickyBroadcast_allSentIntentsShouldBeDeliveredToNewRegistrants() {
contextWrapper.sendStickyBroadcast(new Intent("foo"));
contextWrapper.sendStickyBroadcast(new Intent("baz"));
assertThat(transcript).isEmpty();
BroadcastReceiver receiver = broadcastReceiver("Larry");
Intent sticker = contextWrapper.registerReceiver(receiver, intentFilter("foo", "baz"));
assertThat(transcript).containsExactly("Larry notified of foo", "Larry notified of baz");
/*
Note: we do not strictly test what is returned by the method in this case
because there no guaranties what particular Intent will be returned by Android system
*/
assertThat(sticker).isNotNull();
}
@Test
public void shouldReturnSameApplicationEveryTime() throws Exception {
Activity activity = new Activity();
assertThat(activity.getApplication()).isSameAs(activity.getApplication());
assertThat(activity.getApplication()).isSameAs(new Activity().getApplication());
}
@Test
public void shouldReturnSameApplicationContextEveryTime() throws Exception {
Activity activity = Robolectric.setupActivity(Activity.class);
assertThat(activity.getApplicationContext()).isSameAs(activity.getApplicationContext());
assertThat(activity.getApplicationContext()).isSameAs(Robolectric.setupActivity(Activity.class).getApplicationContext());
}
@Test
public void shouldReturnApplicationContext_forViewContextInflatedWithApplicationContext() throws Exception {
View view = LayoutInflater.from(RuntimeEnvironment.application).inflate(R.layout.custom_layout, null);
Context viewContext = new ContextWrapper(view.getContext());
assertThat(viewContext.getApplicationContext()).isEqualTo(RuntimeEnvironment.application);
}
@Test
public void shouldReturnSameContentResolverEveryTime() throws Exception {
Activity activity = Robolectric.setupActivity(Activity.class);
assertThat(activity.getContentResolver()).isSameAs(activity.getContentResolver());
assertThat(activity.getContentResolver()).isSameAs(Robolectric.setupActivity(Activity.class).getContentResolver());
}
@Test
public void shouldReturnSameLocationManagerEveryTime() throws Exception {
assertSameInstanceEveryTime(Context.LOCATION_SERVICE);
}
@Test
public void shouldReturnSameWifiManagerEveryTime() throws Exception {
assertSameInstanceEveryTime(Context.WIFI_SERVICE);
}
@Test
public void shouldReturnSameAlarmServiceEveryTime() throws Exception {
assertSameInstanceEveryTime(Context.ALARM_SERVICE);
}
@Test
public void checkPermissionsShouldReturnPermissionGrantedToAddedPermissions() throws Exception {
shadowOf(contextWrapper).grantPermissions("foo", "bar");
assertThat(contextWrapper.checkPermission("foo", 0, 0)).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkPermission("bar", 0, 0)).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkPermission("baz", 0, 0)).isEqualTo(PERMISSION_DENIED);
}
private void assertSameInstanceEveryTime(String serviceName) {
Activity activity1 = buildActivity(Activity.class).create().get();
Activity activity2 = buildActivity(Activity.class).create().get();
assertThat(activity1.getSystemService(serviceName)).isSameAs(activity1.getSystemService(serviceName));
assertThat(activity1.getSystemService(serviceName)).isSameAs(activity2.getSystemService(serviceName));
}
@Test
public void bindServiceDelegatesToShadowApplication() {
contextWrapper.bindService(new Intent("foo"), new TestService(), Context.BIND_AUTO_CREATE);
assertEquals("foo", shadowOf(RuntimeEnvironment.application).getNextStartedService().getAction());
}
@Test
public void startActivities_shouldStartAllActivities() {
final Intent view = new Intent(Intent.ACTION_VIEW);
final Intent pick = new Intent(Intent.ACTION_PICK);
contextWrapper.startActivities(new Intent[] {view, pick});
assertThat(ShadowApplication.getInstance().getNextStartedActivity()).isEqualTo(pick);
assertThat(ShadowApplication.getInstance().getNextStartedActivity()).isEqualTo(view);
}
@Test
public void startActivities_withBundle_shouldStartAllActivities() {
final Intent view = new Intent(Intent.ACTION_VIEW);
final Intent pick = new Intent(Intent.ACTION_PICK);
contextWrapper.startActivities(new Intent[] {view, pick}, new Bundle());
assertThat(ShadowApplication.getInstance().getNextStartedActivity()).isEqualTo(pick);
assertThat(ShadowApplication.getInstance().getNextStartedActivity()).isEqualTo(view);
}
private BroadcastReceiver broadcastReceiver(final String name) {
return new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
transcript.add(name + " notified of " + intent.getAction());
}
};
}
private IntentFilter intentFilter(String... actions) {
IntentFilter larryIntentFilter = new IntentFilter();
for (String action : actions) {
larryIntentFilter.addAction(action);
}
return larryIntentFilter;
}
@Test
public void packageManagerShouldNotBeNullWhenWrappingAnApplication() {
assertThat(RuntimeEnvironment.application.getPackageManager()).isNotNull();
}
@Test
public void checkCallingPermissionsShouldReturnPermissionGrantedToAddedPermissions() throws Exception {
shadowOf(contextWrapper).grantPermissions("foo", "bar");
assertThat(contextWrapper.checkCallingPermission("foo")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingPermission("bar")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingPermission("baz")).isEqualTo(PERMISSION_DENIED);
}
@Test
public void checkCallingOrSelfPermissionsShouldReturnPermissionGrantedToAddedPermissions() throws Exception {
shadowOf(contextWrapper).grantPermissions("foo", "bar");
assertThat(contextWrapper.checkCallingOrSelfPermission("foo")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingOrSelfPermission("bar")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingOrSelfPermission("baz")).isEqualTo(PERMISSION_DENIED);
}
@Test
public void checkCallingPermission_shouldReturnPermissionDeniedForRemovedPermissions() throws Exception {
shadowOf(contextWrapper).grantPermissions("foo", "bar");
shadowOf(contextWrapper).denyPermissions("foo", "qux");
assertThat(contextWrapper.checkCallingPermission("foo")).isEqualTo(PERMISSION_DENIED);
assertThat(contextWrapper.checkCallingPermission("bar")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingPermission("baz")).isEqualTo(PERMISSION_DENIED);
assertThat(contextWrapper.checkCallingPermission("qux")).isEqualTo(PERMISSION_DENIED);
}
@Test
public void checkCallingOrSelfPermission_shouldReturnPermissionDeniedForRemovedPermissions() throws Exception {
shadowOf(contextWrapper).grantPermissions("foo", "bar");
shadowOf(contextWrapper).denyPermissions("foo", "qux");
assertThat(contextWrapper.checkCallingOrSelfPermission("foo")).isEqualTo(PERMISSION_DENIED);
assertThat(contextWrapper.checkCallingOrSelfPermission("bar")).isEqualTo(PERMISSION_GRANTED);
assertThat(contextWrapper.checkCallingOrSelfPermission("baz")).isEqualTo(PERMISSION_DENIED);
assertThat(contextWrapper.checkCallingOrSelfPermission("qux")).isEqualTo(PERMISSION_DENIED);
}
@Test
public void getSharedPreferencesShouldReturnSameInstanceWhenSameNameIsSupplied() {
final SharedPreferences pref1 = contextWrapper.getSharedPreferences("pref", Context.MODE_PRIVATE);
final SharedPreferences pref2 = contextWrapper.getSharedPreferences("pref", Context.MODE_PRIVATE);
assertThat(pref1).isSameAs(pref2);
}
@Test
public void getSharedPreferencesShouldReturnDifferentInstancesWhenDifferentNameIsSupplied() {
final SharedPreferences pref1 = contextWrapper.getSharedPreferences("pref1", Context.MODE_PRIVATE);
final SharedPreferences pref2 = contextWrapper.getSharedPreferences("pref2", Context.MODE_PRIVATE);
assertThat(pref1).isNotSameAs(pref2);
}
@Test
public void sendBroadcast_shouldOnlySendIntentWithTypeWhenReceiverMatchesType()
throws IntentFilter.MalformedMimeTypeException {
final BroadcastReceiver viewAllTypesReceiver = broadcastReceiver("ViewActionWithAnyTypeReceiver");
final IntentFilter allTypesIntentFilter = intentFilter("view");
allTypesIntentFilter.addDataType("*/*");
contextWrapper.registerReceiver(viewAllTypesReceiver, allTypesIntentFilter);
final BroadcastReceiver imageReceiver = broadcastReceiver("ImageReceiver");
final IntentFilter imageIntentFilter = intentFilter("view");
imageIntentFilter.addDataType("img/*");
contextWrapper.registerReceiver(imageReceiver, imageIntentFilter);
final BroadcastReceiver videoReceiver = broadcastReceiver("VideoReceiver");
final IntentFilter videoIntentFilter = intentFilter("view");
videoIntentFilter.addDataType("video/*");
contextWrapper.registerReceiver(videoReceiver, videoIntentFilter);
final BroadcastReceiver viewReceiver = broadcastReceiver("ViewActionReceiver");
final IntentFilter viewIntentFilter = intentFilter("view");
contextWrapper.registerReceiver(viewReceiver, viewIntentFilter);
final Intent imageIntent = new Intent("view");
imageIntent.setType("img/jpeg");
contextWrapper.sendBroadcast(imageIntent);
final Intent videoIntent = new Intent("view");
videoIntent.setType("video/mp4");
contextWrapper.sendBroadcast(videoIntent);
assertThat(transcript).containsExactly(
"ViewActionWithAnyTypeReceiver notified of view",
"ImageReceiver notified of view",
"ViewActionWithAnyTypeReceiver notified of view",
"VideoReceiver notified of view");
}
@Test
public void getApplicationInfo_shouldReturnApplicationInfoForApplicationPackage() {
final ApplicationInfo info = contextWrapper.getApplicationInfo();
assertThat(info.packageName).isEqualTo("org.robolectric");
}
@Test
public void getApplicationInfo_whenPackageManagerIsNull_shouldNotExplode() {
RuntimeEnvironment.setRobolectricPackageManager(null);
contextWrapper.getApplicationInfo();
}
}