1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.example.spinner;
18 
19 import com.android.example.spinner.R;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.SharedPreferences;
24 import android.os.Bundle;
25 import android.view.View;
26 import android.widget.AdapterView;
27 import android.widget.ArrayAdapter;
28 import android.widget.Spinner;
29 import android.widget.TextView;
30 import android.widget.Toast;
31 import android.widget.AdapterView.OnItemSelectedListener;
32 
33 /**
34  * Displays an Android spinner widget backed by data in an array. The
35  * array is loaded from the strings.xml resources file.
36  */
37 public class SpinnerActivity extends Activity {
38 
39     /**
40      * Fields to contain the current position and display contents of the spinner
41      */
42     protected int mPos;
43     protected String mSelection;
44 
45     /**
46      * ArrayAdapter connects the spinner widget to array-based data.
47      */
48     protected ArrayAdapter<CharSequence> mAdapter;
49 
50     /**
51      *  The initial position of the spinner when it is first installed.
52      */
53     public static final int DEFAULT_POSITION = 2;
54 
55     /**
56      * The name of a properties file that stores the position and
57      * selection when the activity is not loaded.
58      */
59     public static final String PREFERENCES_FILE = "SpinnerPrefs";
60 
61     /**
62      * These values are used to read and write the properties file.
63      * PROPERTY_DELIMITER delimits the key and value in a Java properties file.
64      * The "marker" strings are used to write the properties into the file
65      */
66     public static final String PROPERTY_DELIMITER = "=";
67 
68     /**
69      * The key or label for "position" in the preferences file
70      */
71     public static final String POSITION_KEY = "Position";
72 
73     /**
74      * The key or label for "selection" in the preferences file
75      */
76     public static final String SELECTION_KEY = "Selection";
77 
78     public static final String POSITION_MARKER =
79             POSITION_KEY + PROPERTY_DELIMITER;
80 
81     public static final String SELECTION_MARKER =
82             SELECTION_KEY + PROPERTY_DELIMITER;
83 
84     /**
85      * Initializes the application and the activity.
86      * 1) Sets the view
87      * 2) Reads the spinner's backing data from the string resources file
88      * 3) Instantiates a callback listener for handling selection from the
89      *    spinner
90      * Notice that this method includes code that can be uncommented to force
91      * tests to fail.
92      *
93      * This method overrides the default onCreate() method for an Activity.
94      *
95      * @see android.app.Activity#onCreate(android.os.Bundle)
96      */
97     @Override
onCreate(Bundle savedInstanceState)98     public void onCreate(Bundle savedInstanceState) {
99 
100         /**
101          * derived classes that use onCreate() overrides must always call the super constructor
102          */
103         super.onCreate(savedInstanceState);
104 
105         setContentView(R.layout.main);
106 
107         Spinner spinner = (Spinner) findViewById(R.id.Spinner01);
108 
109         /*
110          * Create a backing mLocalAdapter for the Spinner from a list of the
111          * planets. The list is defined by XML in the strings.xml file.
112          */
113 
114         this.mAdapter = ArrayAdapter.createFromResource(this, R.array.Planets,
115                 android.R.layout.simple_spinner_dropdown_item);
116 
117         /*
118          * Attach the mLocalAdapter to the spinner.
119          */
120 
121         spinner.setAdapter(this.mAdapter);
122 
123         /*
124          * Create a listener that is triggered when Android detects the
125          * user has selected an item in the Spinner.
126          */
127 
128         OnItemSelectedListener spinnerListener = new myOnItemSelectedListener(this,this.mAdapter);
129 
130         /*
131          * Attach the listener to the Spinner.
132          */
133 
134         spinner.setOnItemSelectedListener(spinnerListener);
135 
136 
137         /*
138          * To demonstrate a failure in the preConditions test,
139          * uncomment the following line.
140          * The test will fail because the selection listener for the
141          * Spinner is not set.
142          */
143          // spinner.setOnItemSelectedListener(null);
144 
145     }
146 
147 
148     /**
149      *  A callback listener that implements the
150      *  {@link android.widget.AdapterView.OnItemSelectedListener} interface
151      *  For views based on adapters, this interface defines the methods available
152      *  when the user selects an item from the View.
153      *
154      */
155     public class myOnItemSelectedListener implements OnItemSelectedListener {
156 
157         /*
158          * provide local instances of the mLocalAdapter and the mLocalContext
159          */
160 
161         ArrayAdapter<CharSequence> mLocalAdapter;
162         Activity mLocalContext;
163 
164         /**
165          *  Constructor
166          *  @param c - The activity that displays the Spinner.
167          *  @param ad - The Adapter view that
168          *    controls the Spinner.
169          *  Instantiate a new listener object.
170          */
myOnItemSelectedListener(Activity c, ArrayAdapter<CharSequence> ad)171         public myOnItemSelectedListener(Activity c, ArrayAdapter<CharSequence> ad) {
172 
173           this.mLocalContext = c;
174           this.mLocalAdapter = ad;
175 
176         }
177 
178         /**
179          * When the user selects an item in the spinner, this method is invoked by the callback
180          * chain. Android calls the item selected listener for the spinner, which invokes the
181          * onItemSelected method.
182          *
183          * @see android.widget.AdapterView.OnItemSelectedListener#onItemSelected(
184          *  android.widget.AdapterView, android.view.View, int, long)
185          * @param parent - the AdapterView for this listener
186          * @param v - the View for this listener
187          * @param pos - the 0-based position of the selection in the mLocalAdapter
188          * @param row - the 0-based row number of the selection in the View
189          */
onItemSelected(AdapterView<?> parent, View v, int pos, long row)190         public void onItemSelected(AdapterView<?> parent, View v, int pos, long row) {
191 
192             SpinnerActivity.this.mPos = pos;
193             SpinnerActivity.this.mSelection = parent.getItemAtPosition(pos).toString();
194             /*
195              * Set the value of the text field in the UI
196              */
197             TextView resultText = (TextView)findViewById(R.id.SpinnerResult);
198             resultText.setText(SpinnerActivity.this.mSelection);
199         }
200 
201         /**
202          * The definition of OnItemSelectedListener requires an override
203          * of onNothingSelected(), even though this implementation does not use it.
204          * @param parent - The View for this Listener
205          */
onNothingSelected(AdapterView<?> parent)206         public void onNothingSelected(AdapterView<?> parent) {
207 
208             // do nothing
209 
210         }
211     }
212 
213     /**
214      * Restores the current state of the spinner (which item is selected, and the value
215      * of that item).
216      * Since onResume() is always called when an Activity is starting, even if it is re-displaying
217      * after being hidden, it is the best place to restore state.
218      *
219      * Attempts to read the state from a preferences file. If this read fails,
220      * assume it was just installed, so do an initialization. Regardless, change the
221      * state of the spinner to be the previous position.
222      *
223      * @see android.app.Activity#onResume()
224      */
225     @Override
onResume()226     public void onResume() {
227 
228         /*
229          * an override to onResume() must call the super constructor first.
230          */
231 
232         super.onResume();
233 
234         /*
235          * Try to read the preferences file. If not found, set the state to the desired initial
236          * values.
237          */
238 
239         if (!readInstanceState(this)) setInitialState();
240 
241         /*
242          * Set the spinner to the current state.
243          */
244 
245         Spinner restoreSpinner = (Spinner)findViewById(R.id.Spinner01);
246         restoreSpinner.setSelection(getSpinnerPosition());
247 
248     }
249 
250     /**
251      * Store the current state of the spinner (which item is selected, and the value of that item).
252      * Since onPause() is always called when an Activity is about to be hidden, even if it is about
253      * to be destroyed, it is the best place to save state.
254      *
255      * Attempt to write the state to the preferences file. If this fails, notify the user.
256      *
257      * @see android.app.Activity#onPause()
258      */
259     @Override
onPause()260     public void onPause() {
261 
262         /*
263          * an override to onPause() must call the super constructor first.
264          */
265 
266         super.onPause();
267 
268         /*
269          * Save the state to the preferences file. If it fails, display a Toast, noting the failure.
270          */
271 
272         if (!writeInstanceState(this)) {
273              Toast.makeText(this,
274                      "Failed to write state!", Toast.LENGTH_LONG).show();
275           }
276     }
277 
278     /**
279      * Sets the initial state of the spinner when the application is first run.
280      */
setInitialState()281     public void setInitialState() {
282 
283         this.mPos = DEFAULT_POSITION;
284 
285     }
286 
287     /**
288      * Read the previous state of the spinner from the preferences file
289      * @param c - The Activity's Context
290      */
readInstanceState(Context c)291     public boolean readInstanceState(Context c) {
292 
293         /*
294          * The preferences are stored in a SharedPreferences file. The abstract implementation of
295          * SharedPreferences is a "file" containing a hashmap. All instances of an application
296          * share the same instance of this file, which means that all instances of an application
297          * share the same preference settings.
298          */
299 
300         /*
301          * Get the SharedPreferences object for this application
302          */
303 
304         SharedPreferences p = c.getSharedPreferences(PREFERENCES_FILE, MODE_WORLD_READABLE);
305         /*
306          * Get the position and value of the spinner from the file, or a default value if the
307          * key-value pair does not exist.
308          */
309         this.mPos = p.getInt(POSITION_KEY, SpinnerActivity.DEFAULT_POSITION);
310         this.mSelection = p.getString(SELECTION_KEY, "");
311 
312         /*
313          * SharedPreferences doesn't fail if the code tries to get a non-existent key. The
314          * most straightforward way to indicate success is to return the results of a test that
315          * SharedPreferences contained the position key.
316          */
317 
318           return (p.contains(POSITION_KEY));
319 
320         }
321 
322     /**
323      * Write the application's current state to a properties repository.
324      * @param c - The Activity's Context
325      *
326      */
writeInstanceState(Context c)327     public boolean writeInstanceState(Context c) {
328 
329         /*
330          * Get the SharedPreferences object for this application
331          */
332 
333         SharedPreferences p =
334                 c.getSharedPreferences(SpinnerActivity.PREFERENCES_FILE, MODE_WORLD_READABLE);
335 
336         /*
337          * Get the editor for this object. The editor interface abstracts the implementation of
338          * updating the SharedPreferences object.
339          */
340 
341         SharedPreferences.Editor e = p.edit();
342 
343         /*
344          * Write the keys and values to the Editor
345          */
346 
347         e.putInt(POSITION_KEY, this.mPos);
348         e.putString(SELECTION_KEY, this.mSelection);
349 
350         /*
351          * Commit the changes. Return the result of the commit. The commit fails if Android
352          * failed to commit the changes to persistent storage.
353          */
354 
355         return (e.commit());
356 
357     }
358 
getSpinnerPosition()359     public int getSpinnerPosition() {
360         return this.mPos;
361     }
362 
setSpinnerPosition(int pos)363     public void setSpinnerPosition(int pos) {
364         this.mPos = pos;
365     }
366 
getSpinnerSelection()367     public String getSpinnerSelection() {
368         return this.mSelection;
369     }
370 
setSpinnerSelection(String selection)371     public void setSpinnerSelection(String selection) {
372         this.mSelection = selection;
373     }
374 }
375