| package com.xtremelabs.robolectric.shadows; |
| |
| import android.app.Activity; |
| import android.app.Dialog; |
| import android.appwidget.AppWidgetProvider; |
| import android.content.*; |
| import android.content.pm.ActivityInfo; |
| import android.database.CharArrayBuffer; |
| import android.database.ContentObserver; |
| import android.database.Cursor; |
| import android.database.DataSetObserver; |
| import android.database.sqlite.SQLiteCursor; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.widget.FrameLayout; |
| import com.xtremelabs.robolectric.ApplicationResolver; |
| import com.xtremelabs.robolectric.R; |
| import com.xtremelabs.robolectric.Robolectric; |
| import com.xtremelabs.robolectric.WithTestDefaultsRunner; |
| import com.xtremelabs.robolectric.util.TestRunnable; |
| import com.xtremelabs.robolectric.util.Transcript; |
| import org.hamcrest.CoreMatchers; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import static com.xtremelabs.robolectric.Robolectric.shadowOf; |
| import static com.xtremelabs.robolectric.util.TestUtil.assertInstanceOf; |
| import static com.xtremelabs.robolectric.util.TestUtil.newConfig; |
| import static org.hamcrest.CoreMatchers.*; |
| import static org.hamcrest.core.StringStartsWith.startsWith; |
| import static org.junit.Assert.*; |
| |
| @RunWith(WithTestDefaultsRunner.class) |
| public class ActivityTest { |
| @Test(expected = IllegalStateException.class) |
| public void shouldComplainIfActivityIsDestroyedWithRegisteredBroadcastReceivers() throws Exception { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| activity.registerReceiver(new AppWidgetProvider(), new IntentFilter()); |
| activity.onDestroy(); |
| } |
| |
| @Test |
| public void shouldNotComplainIfActivityIsDestroyedWhileAnotherActivityHasRegisteredBroadcastReceivers() throws Exception { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| |
| DialogLifeCycleActivity activity2 = new DialogLifeCycleActivity(); |
| activity2.registerReceiver(new AppWidgetProvider(), new IntentFilter()); |
| |
| activity.onDestroy(); // should not throw exception |
| } |
| |
| @Test |
| public void shouldNotRegisterNullBroadcastReceiver() { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| activity.registerReceiver(null, new IntentFilter()); |
| |
| activity.onDestroy(); |
| } |
| |
| @Test |
| public void startActivityForResultAndReceiveResult_shouldSendResponsesBackToActivity() throws Exception { |
| final Transcript transcript = new Transcript(); |
| Activity activity = new Activity() { |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| transcript.add("onActivityResult called with requestCode " + requestCode + ", resultCode " + resultCode + ", intent data " + data.getData()); |
| } |
| }; |
| activity.startActivityForResult(new Intent().setType("audio/*"), 123); |
| activity.startActivityForResult(new Intent().setType("image/*"), 456); |
| |
| shadowOf(activity).receiveResult(new Intent().setType("image/*"), Activity.RESULT_OK, |
| new Intent().setData(Uri.parse("content:foo"))); |
| transcript.assertEventsSoFar("onActivityResult called with requestCode 456, resultCode -1, intent data content:foo"); |
| } |
| |
| @Test |
| public void startActivityForResultAndReceiveResult_whenNoIntentMatches_shouldThrowException() throws Exception { |
| Activity activity = new Activity() { |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| throw new IllegalStateException("should not be called"); |
| } |
| }; |
| activity.startActivityForResult(new Intent().setType("audio/*"), 123); |
| activity.startActivityForResult(new Intent().setType("image/*"), 456); |
| |
| Intent requestIntent = new Intent().setType("video/*"); |
| try { |
| shadowOf(activity).receiveResult(requestIntent, Activity.RESULT_OK, |
| new Intent().setData(Uri.parse("content:foo"))); |
| fail(); |
| } catch (Exception e) { |
| assertThat(e.getMessage(), startsWith("No intent matches " + requestIntent)); |
| } |
| } |
| |
| @Test |
| public void shouldSupportStartActivityForResult() throws Exception { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| ShadowActivity shadowActivity = Robolectric.shadowOf(activity); |
| Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class); |
| assertThat(shadowActivity.getNextStartedActivity(), nullValue()); |
| |
| activity.startActivityForResult(intent, 142); |
| |
| Intent startedIntent = shadowActivity.getNextStartedActivity(); |
| assertThat(startedIntent, notNullValue()); |
| assertThat(startedIntent, sameInstance(intent)); |
| } |
| |
| @Test |
| public void shouldSupportGetStartedActitivitesForResult() throws Exception { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| ShadowActivity shadowActivity = Robolectric.shadowOf(activity); |
| Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class); |
| |
| activity.startActivityForResult(intent, 142); |
| |
| ShadowActivity.IntentForResult intentForResult = shadowActivity.getNextStartedActivityForResult(); |
| assertThat(intentForResult, notNullValue()); |
| assertThat(shadowActivity.getNextStartedActivityForResult(), nullValue()); |
| assertThat(intentForResult.intent, notNullValue()); |
| assertThat(intentForResult.intent, sameInstance(intent)); |
| assertThat(intentForResult.requestCode, equalTo(142)); |
| } |
| |
| @Test |
| public void shouldSupportPeekStartedActitivitesForResult() throws Exception { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| ShadowActivity shadowActivity = Robolectric.shadowOf(activity); |
| Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class); |
| |
| activity.startActivityForResult(intent, 142); |
| |
| ShadowActivity.IntentForResult intentForResult = shadowActivity.peekNextStartedActivityForResult(); |
| assertThat(intentForResult, notNullValue()); |
| assertThat(shadowActivity.peekNextStartedActivityForResult(), sameInstance(intentForResult)); |
| assertThat(intentForResult.intent, notNullValue()); |
| assertThat(intentForResult.intent, sameInstance(intent)); |
| assertThat(intentForResult.requestCode, equalTo(142)); |
| } |
| |
| @Test |
| public void onContentChangedShouldBeCalledAfterContentViewIsSet() throws RuntimeException { |
| final Transcript transcript = new Transcript(); |
| Activity customActivity = new Activity() { |
| @Override |
| public void onContentChanged() { |
| transcript.add("onContentChanged was called; title is \"" + shadowOf(findViewById(R.id.title)).innerText() + "\""); |
| } |
| }; |
| customActivity.setContentView(R.layout.main); |
| transcript.assertEventsSoFar("onContentChanged was called; title is \"Main Layout\""); |
| } |
| |
| @Test |
| public void shouldRetrievePackageNameFromTheManifest() throws Exception { |
| Robolectric.application = new ApplicationResolver(newConfig("TestAndroidManifestWithPackageName.xml")).resolveApplication(); |
| assertThat("com.wacka.wa", equalTo(new Activity().getPackageName())); |
| } |
| |
| @Test |
| public void shouldRunUiTasksImmediatelyByDefault() throws Exception { |
| TestRunnable runnable = new TestRunnable(); |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| activity.runOnUiThread(runnable); |
| assertTrue(runnable.wasRun); |
| } |
| |
| @Test |
| public void shouldQueueUiTasksWhenUiThreadIsPaused() throws Exception { |
| Robolectric.pauseMainLooper(); |
| |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| TestRunnable runnable = new TestRunnable(); |
| activity.runOnUiThread(runnable); |
| assertFalse(runnable.wasRun); |
| |
| Robolectric.unPauseMainLooper(); |
| assertTrue(runnable.wasRun); |
| } |
| |
| @Test |
| public void showDialog_shouldCreatePrepareAndShowDialog() { |
| final DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| final AtomicBoolean dialogWasShown = new AtomicBoolean(false); |
| |
| new Dialog(activity) { |
| { |
| activity.dialog = this; |
| } |
| |
| @Override |
| public void show() { |
| dialogWasShown.set(true); |
| } |
| }; |
| |
| activity.showDialog(1); |
| |
| assertTrue(activity.createdDialog); |
| assertTrue(activity.preparedDialog); |
| assertTrue(dialogWasShown.get()); |
| } |
| |
| @Test |
| public void showDialog_shouldCreatePrepareAndShowDialogWithBundle() { |
| final DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| final AtomicBoolean dialogWasShown = new AtomicBoolean(false); |
| |
| new Dialog(activity) { |
| { |
| activity.dialog = this; |
| } |
| |
| @Override |
| public void show() { |
| dialogWasShown.set(true); |
| } |
| }; |
| |
| activity.showDialog(1, new Bundle()); |
| |
| assertTrue(activity.createdDialog); |
| assertTrue(activity.preparedDialogWithBundle); |
| assertTrue(dialogWasShown.get()); |
| } |
| |
| @Test |
| public void showDialog_shouldReuseDialogs() { |
| final DialogCreatingActivity activity = new DialogCreatingActivity(); |
| |
| activity.showDialog(1); |
| |
| Dialog firstDialog = ShadowDialog.getLatestDialog(); |
| |
| activity.showDialog(1); |
| |
| final Dialog secondDialog = ShadowDialog.getLatestDialog(); |
| |
| assertSame("dialogs should be the same instance", firstDialog, secondDialog); |
| } |
| |
| @Test |
| public void showDialog_shouldShowDialog() throws Exception { |
| final DialogCreatingActivity activity = new DialogCreatingActivity(); |
| activity.showDialog(1); |
| Dialog dialog = ShadowDialog.getLatestDialog(); |
| assertTrue(dialog.isShowing()); |
| } |
| |
| @Test |
| public void dismissDialog_shouldDismissPreviouslyShownDialog() throws Exception { |
| final DialogCreatingActivity activity = new DialogCreatingActivity(); |
| activity.showDialog(1); |
| activity.dismissDialog(1); |
| Dialog dialog = ShadowDialog.getLatestDialog(); |
| assertFalse(dialog.isShowing()); |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void dismissDialog_shouldThrowExceptionIfDialogWasNotPreviouslyShown() throws Exception { |
| final DialogCreatingActivity activity = new DialogCreatingActivity(); |
| activity.dismissDialog(1); |
| } |
| |
| @Test |
| public void removeDialog_shouldCreateDialogAgain() { |
| final DialogCreatingActivity activity = new DialogCreatingActivity(); |
| |
| activity.showDialog(1); |
| Dialog firstDialog = ShadowDialog.getLatestDialog(); |
| |
| activity.removeDialog(1); |
| assertNull(Robolectric.shadowOf(activity).getDialogById(1)); |
| |
| activity.showDialog(1); |
| Dialog secondDialog = ShadowDialog.getLatestDialog(); |
| |
| assertNotSame("dialogs should not be the same instance", firstDialog, secondDialog); |
| } |
| |
| @Test |
| public void shouldCallOnCreateDialogFromShowDialog() { |
| ActivityWithOnCreateDialog activity = new ActivityWithOnCreateDialog(); |
| activity.showDialog(123); |
| assertTrue(activity.onCreateDialogWasCalled); |
| assertThat(ShadowDialog.getLatestDialog(), CoreMatchers.<Object>notNullValue()); |
| } |
| |
| @Test |
| public void shouldCallFinishInOnBackPressed() { |
| Activity activity = new Activity(); |
| activity.onBackPressed(); |
| |
| ShadowActivity shadowActivity = shadowOf(activity); |
| assertTrue(shadowActivity.isFinishing()); |
| } |
| |
| @Test |
| public void shouldSupportCurrentFocus() { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| ShadowActivity shadow = shadowOf(activity); |
| |
| assertNull(shadow.getCurrentFocus()); |
| View view = new View(activity); |
| shadow.setCurrentFocus(view); |
| assertEquals(view, shadow.getCurrentFocus()); |
| } |
| |
| @Test |
| public void shouldSetOrientation() { |
| DialogLifeCycleActivity activity = new DialogLifeCycleActivity(); |
| activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); |
| assertThat(activity.getRequestedOrientation(), equalTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)); |
| } |
| |
| @Test |
| public void retrieveIdOfResource() { |
| Activity activity = new Activity(); |
| |
| int id1 = R.string.hello; |
| String string = activity.getString(id1); |
| assertEquals("Hello", string); |
| |
| int id = activity.getResources().getIdentifier("hello", "string", "com.xtremelabs.robolectric"); |
| assertTrue(id > 0); |
| |
| String hello = activity.getResources().getString(id); |
| assertEquals("Hello", hello); |
| } |
| |
| @Test |
| public void getCurrentFocus_shouldBeNullWhenNoFocusRequested() { |
| Activity activity = new Activity(); |
| activity.setContentView(R.layout.main); |
| |
| View focusedView = shadowOf(activity).getCurrentFocus(); |
| assertNull(focusedView); |
| } |
| |
| @Test |
| public void getCurrentFocus_shouldReturnSubViewAfterFocusedRequest() { |
| Activity activity = new Activity(); |
| activity.setContentView(R.layout.main); |
| |
| View view = activity.findViewById(R.id.button); |
| view.requestFocus(); |
| |
| View focusedView = shadowOf(activity).getCurrentFocus(); |
| assertEquals(R.id.button, focusedView.getId()); |
| } |
| |
| @Test |
| public void retrieveIdOfNonExistingResource() { |
| Activity activity = new Activity(); |
| |
| int id = activity.getResources().getIdentifier("just_alot_of_crap", "string", "com.xtremelabs.robolectric"); |
| assertTrue(id == 0); |
| } |
| |
| @Test |
| public void shouldSetContentViewWithFrameLayoutAsParent() throws Exception { |
| Activity activity = new Activity(); |
| activity.setContentView(R.layout.toplevel_merge); |
| |
| View contentView = shadowOf(activity).getContentView(); |
| assertInstanceOf(FrameLayout.class, contentView); |
| assertThat(((FrameLayout) contentView).getChildCount(), equalTo(2)); |
| } |
| |
| @Test |
| public void onKeyUp_recordsThatItWasCalled() throws Exception { |
| Activity activity = new Activity(); |
| boolean consumed = activity.onKeyUp(KeyEvent.KEYCODE_0, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0)); |
| |
| assertFalse(consumed); |
| assertTrue(shadowOf(activity).onKeyUpWasCalled()); |
| |
| shadowOf(activity).resetKeyUpWasCalled(); |
| assertFalse(shadowOf(activity).onKeyUpWasCalled()); |
| } |
| |
| @Test |
| public void onKeyUp_callsOnBackPressedWhichFinishesTheActivity() throws Exception { |
| Activity activity = new Activity(); |
| boolean consumed = activity.onKeyUp(KeyEvent.KEYCODE_BACK, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)); |
| |
| assertTrue(consumed); |
| assertTrue(shadowOf(activity).onKeyUpWasCalled()); |
| assertTrue(activity.isFinishing()); |
| } |
| |
| @Test |
| public void shouldGiveSharedPreferences() throws Exception { |
| Activity activity = new Activity(); |
| SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE); |
| assertNotNull(preferences); |
| preferences.edit().putString("foo", "bar").commit(); |
| assertThat(activity.getPreferences(Context.MODE_PRIVATE).getString("foo", null), equalTo("bar")); |
| } |
| |
| @Test |
| public void shouldFindContentViewContainer() throws Exception { |
| Activity activity = new Activity(); |
| View contentView = new View(activity); |
| activity.setContentView(contentView); |
| |
| FrameLayout contentViewContainer = (FrameLayout) activity.findViewById(android.R.id.content); |
| assertThat(contentViewContainer.getChildAt(0), is(contentView)); |
| } |
| |
| @Test |
| public void createGoesThroughFullLifeCycle() throws Exception { |
| TestActivity activity = new TestActivity(); |
| |
| shadowOf(activity).create(); |
| |
| activity.transcript.assertEventsSoFar( |
| "onCreate", |
| "onStart", |
| "onPostCreate", |
| "onResume" |
| ); |
| } |
| |
| |
| @Test |
| public void recreateGoesThroughFullLifeCycle() throws Exception { |
| TestActivity activity = new TestActivity(); |
| |
| ShadowActivity shadow = shadowOf(activity); |
| shadow.recreate(); |
| |
| activity.transcript.assertEventsSoFar( |
| "onSaveInstanceState", |
| "onPause", |
| "onStop", |
| "onRetainNonConfigurationInstance", |
| "onDestroy", |
| "onCreate", |
| "onStart", |
| "onRestoreInstanceState", |
| "onResume" |
| ); |
| |
| Integer storedValue = (Integer) activity.getLastNonConfigurationInstance(); |
| assertEquals(5, storedValue.intValue()); |
| } |
| |
| @Test |
| public void startAndStopManagingCursorTracksCursors() throws Exception { |
| TestActivity activity = new TestActivity(); |
| |
| ShadowActivity shadow = shadowOf(activity); |
| |
| assertThat( shadow.getManagedCursors(), notNullValue() ); |
| assertThat( shadow.getManagedCursors().size(), equalTo(0) ); |
| |
| Cursor c = Robolectric.newInstanceOf(SQLiteCursor.class); |
| activity.startManagingCursor(c); |
| |
| assertThat( shadow.getManagedCursors(), notNullValue() ); |
| assertThat( shadow.getManagedCursors().size(), equalTo(1) ); |
| assertThat( shadow.getManagedCursors().get(0), sameInstance(c) ); |
| |
| activity.stopManagingCursor(c); |
| |
| assertThat( shadow.getManagedCursors(), notNullValue() ); |
| assertThat( shadow.getManagedCursors().size(), equalTo(0) ); |
| } |
| |
| private static class TestActivity extends Activity { |
| Transcript transcript = new Transcript(); |
| |
| private boolean isRecreating = false; |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| isRecreating = true; |
| transcript.add("onSaveInstanceState"); |
| outState.putString("TestActivityKey", "TestActivityValue"); |
| super.onSaveInstanceState(outState); |
| } |
| |
| @Override |
| public void onRestoreInstanceState(Bundle savedInstanceState) { |
| transcript.add("onRestoreInstanceState"); |
| assertTrue(savedInstanceState.containsKey("TestActivityKey")); |
| assertEquals("TestActivityValue", savedInstanceState.getString("TestActivityKey")); |
| super.onRestoreInstanceState(savedInstanceState); |
| } |
| |
| @Override |
| public Object onRetainNonConfigurationInstance() { |
| transcript.add("onRetainNonConfigurationInstance"); |
| return new Integer(5); |
| } |
| |
| @Override |
| public void onPause() { |
| transcript.add("onPause"); |
| super.onPause(); |
| } |
| |
| @Override |
| public void onDestroy() { |
| transcript.add("onDestroy"); |
| super.onDestroy(); |
| } |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| transcript.add("onCreate"); |
| |
| if( isRecreating ) { |
| assertTrue(savedInstanceState.containsKey("TestActivityKey")); |
| assertEquals("TestActivityValue", savedInstanceState.getString("TestActivityKey")); |
| } |
| |
| super.onCreate(savedInstanceState); |
| } |
| |
| @Override |
| public void onStart() { |
| transcript.add("onStart"); |
| super.onStart(); |
| } |
| |
| @Override |
| public void onPostCreate(Bundle savedInstanceState) { |
| transcript.add("onPostCreate"); |
| super.onPostCreate(savedInstanceState); |
| } |
| |
| @Override |
| public void onStop() { |
| transcript.add("onStop"); |
| super.onStop(); |
| } |
| |
| @Override |
| public void onResume() { |
| transcript.add("onResume"); |
| super.onResume(); |
| } |
| } |
| |
| private static class DialogCreatingActivity extends Activity { |
| @Override |
| protected Dialog onCreateDialog(int id) { |
| return new Dialog(this); |
| } |
| } |
| |
| private static class DialogLifeCycleActivity extends Activity { |
| public boolean createdDialog = false; |
| public boolean preparedDialog = false; |
| public boolean preparedDialogWithBundle = false; |
| public Dialog dialog = null; |
| |
| @Override |
| protected void onDestroy() { |
| super.onDestroy(); |
| } |
| |
| @Override |
| protected Dialog onCreateDialog(int id) { |
| createdDialog = true; |
| return dialog; |
| } |
| |
| @Override |
| protected void onPrepareDialog(int id, Dialog dialog) { |
| preparedDialog = true; |
| } |
| |
| @Override |
| protected void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { |
| preparedDialogWithBundle = true; |
| } |
| } |
| |
| private static class ActivityWithOnCreateDialog extends Activity { |
| boolean onCreateDialogWasCalled = false; |
| |
| @Override |
| protected Dialog onCreateDialog(int id) { |
| onCreateDialogWasCalled = true; |
| return new Dialog(null); |
| } |
| } |
| } |