Spinner Test
//
//src\com\android\example\spinner\SpinnerActivity.java
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.example.spinner;
import com.android.example.spinner.R;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;
/**
* Displays an Android spinner widget backed by data in an array. The
* array is loaded from the strings.xml resources file.
*/
public class SpinnerActivity extends Activity {
/**
* Fields to contain the current position and display contents of the spinner
*/
protected int mPos;
protected String mSelection;
/**
* ArrayAdapter connects the spinner widget to array-based data.
*/
protected ArrayAdapter<CharSequence> mAdapter;
/**
* The initial position of the spinner when it is first installed.
*/
public static final int DEFAULT_POSITION = 2;
/**
* The name of a properties file that stores the position and
* selection when the activity is not loaded.
*/
public static final String PREFERENCES_FILE = "SpinnerPrefs";
/**
* These values are used to read and write the properties file.
* PROPERTY_DELIMITER delimits the key and value in a Java properties file.
* The "marker" strings are used to write the properties into the file
*/
public static final String PROPERTY_DELIMITER = "=";
/**
* The key or label for "position" in the preferences file
*/
public static final String POSITION_KEY = "Position";
/**
* The key or label for "selection" in the preferences file
*/
public static final String SELECTION_KEY = "Selection";
public static final String POSITION_MARKER =
POSITION_KEY + PROPERTY_DELIMITER;
public static final String SELECTION_MARKER =
SELECTION_KEY + PROPERTY_DELIMITER;
/**
* Initializes the application and the activity.
* 1) Sets the view
* 2) Reads the spinner's backing data from the string resources file
* 3) Instantiates a callback listener for handling selection from the
* spinner
* Notice that this method includes code that can be uncommented to force
* tests to fail.
*
* This method overrides the default onCreate() method for an Activity.
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(Bundle savedInstanceState) {
/**
* derived classes that use onCreate() overrides must always call the super constructor
*/
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Spinner spinner = (Spinner) findViewById(R.id.Spinner01);
/*
* Create a backing mLocalAdapter for the Spinner from a list of the
* planets. The list is defined by XML in the strings.xml file.
*/
this.mAdapter = ArrayAdapter.createFromResource(this, R.array.Planets,
android.R.layout.simple_spinner_dropdown_item);
/*
* Attach the mLocalAdapter to the spinner.
*/
spinner.setAdapter(this.mAdapter);
/*
* Create a listener that is triggered when Android detects the
* user has selected an item in the Spinner.
*/
OnItemSelectedListener spinnerListener = new myOnItemSelectedListener(this,this.mAdapter);
/*
* Attach the listener to the Spinner.
*/
spinner.setOnItemSelectedListener(spinnerListener);
/*
* To demonstrate a failure in the preConditions test,
* uncomment the following line.
* The test will fail because the selection listener for the
* Spinner is not set.
*/
// spinner.setOnItemSelectedListener(null);
}
/**
* A callback listener that implements the
* {@link android.widget.AdapterView.OnItemSelectedListener} interface
* For views based on adapters, this interface defines the methods available
* when the user selects an item from the View.
*
*/
public class myOnItemSelectedListener implements OnItemSelectedListener {
/*
* provide local instances of the mLocalAdapter and the mLocalContext
*/
ArrayAdapter<CharSequence> mLocalAdapter;
Activity mLocalContext;
/**
* Constructor
* @param c - The activity that displays the Spinner.
* @param ad - The Adapter view that
* controls the Spinner.
* Instantiate a new listener object.
*/
public myOnItemSelectedListener(Activity c, ArrayAdapter<CharSequence> ad) {
this.mLocalContext = c;
this.mLocalAdapter = ad;
}
/**
* When the user selects an item in the spinner, this method is invoked by the callback
* chain. Android calls the item selected listener for the spinner, which invokes the
* onItemSelected method.
*
* @see android.widget.AdapterView.OnItemSelectedListener#onItemSelected(
* android.widget.AdapterView, android.view.View, int, long)
* @param parent - the AdapterView for this listener
* @param v - the View for this listener
* @param pos - the 0-based position of the selection in the mLocalAdapter
* @param row - the 0-based row number of the selection in the View
*/
public void onItemSelected(AdapterView<?> parent, View v, int pos, long row) {
SpinnerActivity.this.mPos = pos;
SpinnerActivity.this.mSelection = parent.getItemAtPosition(pos).toString();
/*
* Set the value of the text field in the UI
*/
TextView resultText = (TextView)findViewById(R.id.SpinnerResult);
resultText.setText(SpinnerActivity.this.mSelection);
}
/**
* The definition of OnItemSelectedListener requires an override
* of onNothingSelected(), even though this implementation does not use it.
* @param parent - The View for this Listener
*/
public void onNothingSelected(AdapterView<?> parent) {
// do nothing
}
}
/**
* Restores the current state of the spinner (which item is selected, and the value
* of that item).
* Since onResume() is always called when an Activity is starting, even if it is re-displaying
* after being hidden, it is the best place to restore state.
*
* Attempts to read the state from a preferences file. If this read fails,
* assume it was just installed, so do an initialization. Regardless, change the
* state of the spinner to be the previous position.
*
* @see android.app.Activity#onResume()
*/
@Override
public void onResume() {
/*
* an override to onResume() must call the super constructor first.
*/
super.onResume();
/*
* Try to read the preferences file. If not found, set the state to the desired initial
* values.
*/
if (!readInstanceState(this)) setInitialState();
/*
* Set the spinner to the current state.
*/
Spinner restoreSpinner = (Spinner)findViewById(R.id.Spinner01);
restoreSpinner.setSelection(getSpinnerPosition());
}
/**
* Store the current state of the spinner (which item is selected, and the value of that item).
* Since onPause() is always called when an Activity is about to be hidden, even if it is about
* to be destroyed, it is the best place to save state.
*
* Attempt to write the state to the preferences file. If this fails, notify the user.
*
* @see android.app.Activity#onPause()
*/
@Override
public void onPause() {
/*
* an override to onPause() must call the super constructor first.
*/
super.onPause();
/*
* Save the state to the preferences file. If it fails, display a Toast, noting the failure.
*/
if (!writeInstanceState(this)) {
Toast.makeText(this,
"Failed to write state!", Toast.LENGTH_LONG).show();
}
}
/**
* Sets the initial state of the spinner when the application is first run.
*/
public void setInitialState() {
this.mPos = DEFAULT_POSITION;
}
/**
* Read the previous state of the spinner from the preferences file
* @param c - The Activity's Context
*/
public boolean readInstanceState(Context c) {
/*
* The preferences are stored in a SharedPreferences file. The abstract implementation of
* SharedPreferences is a "file" containing a hashmap. All instances of an application
* share the same instance of this file, which means that all instances of an application
* share the same preference settings.
*/
/*
* Get the SharedPreferences object for this application
*/
SharedPreferences p = c.getSharedPreferences(PREFERENCES_FILE, MODE_WORLD_READABLE);
/*
* Get the position and value of the spinner from the file, or a default value if the
* key-value pair does not exist.
*/
this.mPos = p.getInt(POSITION_KEY, SpinnerActivity.DEFAULT_POSITION);
this.mSelection = p.getString(SELECTION_KEY, "");
/*
* SharedPreferences doesn't fail if the code tries to get a non-existent key. The
* most straightforward way to indicate success is to return the results of a test that
* SharedPreferences contained the position key.
*/
return (p.contains(POSITION_KEY));
}
/**
* Write the application's current state to a properties repository.
* @param c - The Activity's Context
*
*/
public boolean writeInstanceState(Context c) {
/*
* Get the SharedPreferences object for this application
*/
SharedPreferences p =
c.getSharedPreferences(SpinnerActivity.PREFERENCES_FILE, MODE_WORLD_READABLE);
/*
* Get the editor for this object. The editor interface abstracts the implementation of
* updating the SharedPreferences object.
*/
SharedPreferences.Editor e = p.edit();
/*
* Write the keys and values to the Editor
*/
e.putInt(POSITION_KEY, this.mPos);
e.putString(SELECTION_KEY, this.mSelection);
/*
* Commit the changes. Return the result of the commit. The commit fails if Android
* failed to commit the changes to persistent storage.
*/
return (e.commit());
}
public int getSpinnerPosition() {
return this.mPos;
}
public void setSpinnerPosition(int pos) {
this.mPos = pos;
}
public String getSpinnerSelection() {
return this.mSelection;
}
public void setSpinnerSelection(String selection) {
this.mSelection = selection;
}
}
//
//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
Creates a Linear Layout View to contain the spinner
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!--
Creates a spinner widget called Spinner01, within the Linear Layout
The prompt text comes from the string "planet_prompt" in strings.xml
-->
<Spinner
android:id="@+id/Spinner01"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:drawSelectorOnTop = "true"
android:prompt = "@string/planet_prompt">
</Spinner>
<!--
Creates a TextView called SpinnerResult, below the spinner.
-->
<TextView
android:id="@+id/SpinnerResult" android:text="Result"
android:layout_height="fill_parent" android:textSize="10pt"
android:textStyle="bold" android:gravity="center"
android:layout_width="fill_parent">
</TextView>
</LinearLayout>
//
//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
The string named "app_name" defines the application's visible name.
The string array "Planets" defines an array of 9 strings. The application loads
this array into the spinner's array adapter.
The string "planet_prompt" defines the prompt for the result text box.
-->
<resources>
<string name="app_name">Spinner</string>
<string-array name="Planets">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
<item>Mars</item>
<item>Jupiter</item>
<item>Saturn</item>
<item>Uranus</item>
<item>Neptune</item>
<item>Pluto</item>
</string-array>
<string name="planet_prompt">Select a planet</string>
</resources>
//
C:\Java_Dev\sdk\Android\android-sdk\samples\android-13\SpinnerTest\src\com\android\example\spinner\test\SpinnerActivityTest.java
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.example.spinner.test;
import com.android.example.spinner.SpinnerActivity;
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.view.KeyEvent;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
/*
* Tests the example application Spinner. Uses the instrumentation test class
* ActivityInstrumentationTestCase2 as its base class. The tests include
* - test initial conditions
* - test the UI
* - state management - preserving state after the app is shut down and restarted, preserving
* state after the app is hidden (paused) and re-displayed (resumed)
*
* Demonstrates the use of JUnit setUp() and assert() methods.
*/
public class SpinnerActivityTest extends ActivityInstrumentationTestCase2<SpinnerActivity> {
// Number of items in the spinner's backing mLocalAdapter
public static final int ADAPTER_COUNT = 9;
// The location of Saturn in the backing mLocalAdapter array (0-based)
public static final int TEST_POSITION = 5;
// Set the initial position of the spinner to zero
public static final int INITIAL_POSITION = 0;
// The initial position corresponds to Mercury
public static final String INITIAL_SELECTION = "Mercury";
// Test values of position and selection for the testStateDestroy test
public static final int TEST_STATE_DESTROY_POSITION = 2;
public static final String TEST_STATE_DESTROY_SELECTION = "Earth";
// Test values of position and selection for the testStatePause test
public static final int TEST_STATE_PAUSE_POSITION = 4;
public static final String TEST_STATE_PAUSE_SELECTION = "Jupiter";
// The Application object for the application under test
private SpinnerActivity mActivity;
// String displayed in the spinner in the app under test
private String mSelection;
// The currently selected position in the spinner in the app under test
private int mPos;
/*
* The Spinner object in the app under test. Used with instrumentation to control the
* app under test.
*/
private Spinner mSpinner;
/*
* The data backing the Spinner in the app under test.
*/
private SpinnerAdapter mPlanetData;
/*
* Constructor for the test class. Required by Android test classes. The constructor
* must call the super constructor, providing the Android package name of the app under test
* and the Java class name of the activity in that application that handles the MAIN intent.
*/
public SpinnerActivityTest() {
super("com.android.example.spinner", SpinnerActivity.class);
}
/*
* Sets up the test environment before each test.
* @see android.test.ActivityInstrumentationTestCase2#setUp()
*/
@Override
protected void setUp() throws Exception {
/*
* Call the super constructor (required by JUnit)
*/
super.setUp();
/*
* prepare to send key events to the app under test by turning off touch mode.
* Must be done before the first call to getActivity()
*/
setActivityInitialTouchMode(false);
/*
* Start the app under test by starting its main activity. The test runner already knows
* which activity this is from the call to the super constructor, as mentioned
* previously. The tests can now use instrumentation to directly access the main
* activity through mActivity.
*/
mActivity = getActivity();
/*
* Get references to objects in the application under test. These are
* tested to ensure that the app under test has initialized correctly.
*/
mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01);
mPlanetData = mSpinner.getAdapter();
}
/*
* Tests the initial values of key objects in the app under test, to ensure the initial
* conditions make sense. If one of these is not initialized correctly, then subsequent
* tests are suspect and should be ignored.
*/
public void testPreconditions() {
/*
* An example of an initialization test. Assert that the item select listener in
* the main Activity is not null (has been set to a valid callback)
*/
assertTrue(mSpinner.getOnItemSelectedListener() != null);
/*
* Test that the spinner's backing mLocalAdapter was initialized correctly.
*/
assertTrue(mPlanetData != null);
/*
* Also ensure that the backing mLocalAdapter has the correct number of entries.
*/
assertEquals(mPlanetData.getCount(), ADAPTER_COUNT);
}
/*
* Tests the UI of the main activity. Sends key events (keystrokes) to the UI, then checks
* if the resulting spinner state is consistent with the attempted selection.
*/
public void testSpinnerUI() {
/*
* Request focus for the spinner widget in the application under test,
* and set its initial position. This code interacts with the app's View
* so it has to run on the app's thread not the test's thread.
*
* To do this, pass the necessary code to the application with
* runOnUiThread(). The parameter is an anonymous Runnable object that
* contains the Java statements put in it by its run() method.
*/
mActivity.runOnUiThread(
new Runnable() {
public void run() {
mSpinner.requestFocus();
mSpinner.setSelection(INITIAL_POSITION);
}
}
);
// Activate the spinner by clicking the center keypad key
this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
// send 5 down arrow keys to the spinner
for (int i = 1; i <= TEST_POSITION; i++) {
this.sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
}
// select the item at the current spinner position
this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
// get the position of the selected item
mPos = mSpinner.getSelectedItemPosition();
/*
* from the spinner's data mLocalAdapter, get the object at the selected position
* (this is a String value)
*/
mSelection = (String)mSpinner.getItemAtPosition(mPos);
/*
* Get the TextView widget that displays the result of selecting an item from the spinner
*/
TextView resultView =
(TextView) mActivity.findViewById(com.android.example.spinner.R.id.SpinnerResult);
// Get the String value in the EditText object
String resultText = (String) resultView.getText();
/*
* Confirm that the EditText contains the same value as the data in the mLocalAdapter
*/
assertEquals(resultText,mSelection);
}
/*
* Tests that the activity under test maintains the spinner state when the activity halts
* and then restarts (for example, if the device reboots). Sets the spinner to a
* certain state, calls finish() on the activity, restarts the activity, and then
* checks that the spinner has the same state.
*
*/
public void testStateDestroy() {
/*
* Set the position and value of the spinner in the Activity. The test runner's
* instrumentation enables this by running the test app and the main app in the same
* process.
*/
mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);
mActivity.setSpinnerSelection(TEST_STATE_DESTROY_SELECTION);
// Halt the Activity by calling Activity.finish() on it
mActivity.finish();
// Restart the activity by calling ActivityInstrumentationTestCase2.getActivity()
mActivity = this.getActivity();
/*
* Get the current position and selection from the activity.
*/
int currentPosition = mActivity.getSpinnerPosition();
String currentSelection = mActivity.getSpinnerSelection();
// test that they are the same.
assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);
assertEquals(TEST_STATE_DESTROY_SELECTION, currentSelection);
}
/*
* Tests that the activity under test maintains the spinner's state when the activity is
* paused and then resumed.
*
* Calls the activity's onResume() method. Changes the spinner's state by
* altering the activity's View. This means the test must run
* on the UI Thread. All the statements in the test method may be run on
* that thread, so instead of using the runOnUiThread() method, the
* @UiThreadTest is used.
*/
@UiThreadTest
public void testStatePause() {
/*
* Get the instrumentation object for this application. This object
* does all the instrumentation work for the test runner
*/
Instrumentation instr = this.getInstrumentation();
/*
* Set the activity's fields for the position and value of the spinner
*/
mActivity.setSpinnerPosition(TEST_STATE_PAUSE_POSITION);
mActivity.setSpinnerSelection(TEST_STATE_PAUSE_SELECTION);
/*
* Use the instrumentation to onPause() on the currently running Activity.
* This analogous to calling finish() in the testStateDestroy() method.
* This way demonstrates using the test class' instrumentation.
*/
instr.callActivityOnPause(mActivity);
/*
* Set the spinner to a test position
*/
mActivity.setSpinnerPosition(0);
mActivity.setSpinnerSelection("");
/*
* Call the activity's onResume() method. This forces the activity
* to restore its state.
*/
instr.callActivityOnResume(mActivity);
/*
* Get the current state of the spinner
*/
int currentPosition = mActivity.getSpinnerPosition();
String currentSelection = mActivity.getSpinnerSelection();
assertEquals(TEST_STATE_PAUSE_POSITION,currentPosition);
assertEquals(TEST_STATE_PAUSE_SELECTION,currentSelection);
}
}
//
C:\Java_Dev\sdk\Android\android-sdk\samples\android-13\SpinnerTest\res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
This defines the test application's name
-->
<resources>
<string name="app_name">SpinnerTest</string>
</resources>
Related examples in the same category