• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.gallery3d.app;
18 
19 import android.app.Activity;
20 import android.content.Intent;
21 import android.content.res.Configuration;
22 import android.os.Bundle;
23 import android.os.Parcelable;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 
27 import com.android.gallery3d.common.Utils;
28 
29 import java.util.Stack;
30 
31 public class StateManager {
32     @SuppressWarnings("unused")
33     private static final String TAG = "StateManager";
34     private boolean mIsResumed = false;
35 
36     private static final String KEY_MAIN = "activity-state";
37     private static final String KEY_DATA = "data";
38     private static final String KEY_STATE = "bundle";
39     private static final String KEY_CLASS = "class";
40 
41     private GalleryActivity mContext;
42     private Stack<StateEntry> mStack = new Stack<StateEntry>();
43     private ActivityState.ResultEntry mResult;
44 
StateManager(GalleryActivity context)45     public StateManager(GalleryActivity context) {
46         mContext = context;
47     }
48 
startState(Class<? extends ActivityState> klass, Bundle data)49     public void startState(Class<? extends ActivityState> klass,
50             Bundle data) {
51         Log.v(TAG, "startState " + klass);
52         ActivityState state = null;
53         try {
54             state = klass.newInstance();
55         } catch (Exception e) {
56             throw new AssertionError(e);
57         }
58         if (!mStack.isEmpty()) {
59             ActivityState top = getTopState();
60             if (mIsResumed) top.onPause();
61         }
62         state.initialize(mContext, data);
63 
64         mStack.push(new StateEntry(data, state));
65         state.onCreate(data, null);
66         if (mIsResumed) state.resume();
67     }
68 
startStateForResult(Class<? extends ActivityState> klass, int requestCode, Bundle data)69     public void startStateForResult(Class<? extends ActivityState> klass,
70             int requestCode, Bundle data) {
71         Log.v(TAG, "startStateForResult " + klass + ", " + requestCode);
72         ActivityState state = null;
73         try {
74             state = klass.newInstance();
75         } catch (Exception e) {
76             throw new AssertionError(e);
77         }
78         state.initialize(mContext, data);
79         state.mResult = new ActivityState.ResultEntry();
80         state.mResult.requestCode = requestCode;
81 
82         if (!mStack.isEmpty()) {
83             ActivityState as = getTopState();
84             as.mReceivedResults = state.mResult;
85             if (mIsResumed) as.onPause();
86         } else {
87             mResult = state.mResult;
88         }
89 
90         mStack.push(new StateEntry(data, state));
91         state.onCreate(data, null);
92         if (mIsResumed) state.resume();
93     }
94 
createOptionsMenu(Menu menu)95     public boolean createOptionsMenu(Menu menu) {
96         if (mStack.isEmpty()) {
97             return false;
98         } else {
99             return getTopState().onCreateActionBar(menu);
100         }
101     }
102 
onConfigurationChange(Configuration config)103     public void onConfigurationChange(Configuration config) {
104         for (StateEntry entry : mStack) {
105             entry.activityState.onConfigurationChanged(config);
106         }
107     }
108 
resume()109     public void resume() {
110         if (mIsResumed) return;
111         mIsResumed = true;
112         if (!mStack.isEmpty()) getTopState().resume();
113     }
114 
pause()115     public void pause() {
116         if (!mIsResumed) return;
117         mIsResumed = false;
118         if (!mStack.isEmpty()) getTopState().onPause();
119     }
120 
notifyActivityResult(int requestCode, int resultCode, Intent data)121     public void notifyActivityResult(int requestCode, int resultCode, Intent data) {
122         getTopState().onStateResult(requestCode, resultCode, data);
123     }
124 
getStateCount()125     public int getStateCount() {
126         return mStack.size();
127     }
128 
itemSelected(MenuItem item)129     public boolean itemSelected(MenuItem item) {
130         if (!mStack.isEmpty()) {
131             if (getTopState().onItemSelected(item)) return true;
132             if (item.getItemId() == android.R.id.home) {
133                 if (mStack.size() > 1) {
134                     getTopState().onBackPressed();
135                 }
136                 return true;
137             }
138         }
139         return false;
140     }
141 
onBackPressed()142     public void onBackPressed() {
143         if (!mStack.isEmpty()) {
144             getTopState().onBackPressed();
145         }
146     }
147 
finishState(ActivityState state)148     void finishState(ActivityState state) {
149         // The finish() request could be rejected (only happens under Monkey),
150         // If it is rejected, we won't close the last page.
151         if (mStack.size() == 1) {
152             Activity activity = (Activity) mContext.getAndroidContext();
153             if (mResult != null) {
154                 activity.setResult(mResult.resultCode, mResult.resultData);
155             }
156             activity.finish();
157             if (!activity.isFinishing()) {
158                 Log.w(TAG, "finish is rejected, keep the last state");
159                 return;
160             }
161             Log.v(TAG, "no more state, finish activity");
162         }
163 
164         Log.v(TAG, "finishState " + state);
165         if (state != mStack.peek().activityState) {
166             if (state.isDestroyed()) {
167                 Log.d(TAG, "The state is already destroyed");
168                 return;
169             } else {
170                 throw new IllegalArgumentException("The stateview to be finished"
171                         + " is not at the top of the stack: " + state + ", "
172                         + mStack.peek().activityState);
173             }
174         }
175 
176         // Remove the top state.
177         mStack.pop();
178         state.mIsFinishing = true;
179         if (mIsResumed) state.onPause();
180         mContext.getGLRoot().setContentPane(null);
181         state.onDestroy();
182 
183         if (!mStack.isEmpty()) {
184             // Restore the immediately previous state
185             ActivityState top = mStack.peek().activityState;
186             if (mIsResumed) top.resume();
187         }
188     }
189 
switchState(ActivityState oldState, Class<? extends ActivityState> klass, Bundle data)190     void switchState(ActivityState oldState,
191             Class<? extends ActivityState> klass, Bundle data) {
192         Log.v(TAG, "switchState " + oldState + ", " + klass);
193         if (oldState != mStack.peek().activityState) {
194             throw new IllegalArgumentException("The stateview to be finished"
195                     + " is not at the top of the stack: " + oldState + ", "
196                     + mStack.peek().activityState);
197         }
198         // Remove the top state.
199         mStack.pop();
200         if (mIsResumed) oldState.onPause();
201         oldState.onDestroy();
202 
203         // Create new state.
204         ActivityState state = null;
205         try {
206             state = klass.newInstance();
207         } catch (Exception e) {
208             throw new AssertionError(e);
209         }
210         state.initialize(mContext, data);
211         mStack.push(new StateEntry(data, state));
212         state.onCreate(data, null);
213         if (mIsResumed) state.resume();
214     }
215 
destroy()216     public void destroy() {
217         Log.v(TAG, "destroy");
218         while (!mStack.isEmpty()) {
219             mStack.pop().activityState.onDestroy();
220         }
221         mStack.clear();
222     }
223 
224     @SuppressWarnings("unchecked")
restoreFromState(Bundle inState)225     public void restoreFromState(Bundle inState) {
226         Log.v(TAG, "restoreFromState");
227         Parcelable list[] = inState.getParcelableArray(KEY_MAIN);
228         for (Parcelable parcelable : list) {
229             Bundle bundle = (Bundle) parcelable;
230             Class<? extends ActivityState> klass =
231                     (Class<? extends ActivityState>) bundle.getSerializable(KEY_CLASS);
232 
233             Bundle data = bundle.getBundle(KEY_DATA);
234             Bundle state = bundle.getBundle(KEY_STATE);
235 
236             ActivityState activityState;
237             try {
238                 Log.v(TAG, "restoreFromState " + klass);
239                 activityState = klass.newInstance();
240             } catch (Exception e) {
241                 throw new AssertionError(e);
242             }
243             activityState.initialize(mContext, data);
244             activityState.onCreate(data, state);
245             mStack.push(new StateEntry(data, activityState));
246         }
247     }
248 
saveState(Bundle outState)249     public void saveState(Bundle outState) {
250         Log.v(TAG, "saveState");
251 
252         Parcelable list[] = new Parcelable[mStack.size()];
253         int i = 0;
254         for (StateEntry entry : mStack) {
255             Bundle bundle = new Bundle();
256             bundle.putSerializable(KEY_CLASS, entry.activityState.getClass());
257             bundle.putBundle(KEY_DATA, entry.data);
258             Bundle state = new Bundle();
259             entry.activityState.onSaveState(state);
260             bundle.putBundle(KEY_STATE, state);
261             Log.v(TAG, "saveState " + entry.activityState.getClass());
262             list[i++] = bundle;
263         }
264         outState.putParcelableArray(KEY_MAIN, list);
265     }
266 
hasStateClass(Class<? extends ActivityState> klass)267     public boolean hasStateClass(Class<? extends ActivityState> klass) {
268         for (StateEntry entry : mStack) {
269             if (klass.isInstance(entry.activityState)) {
270                 return true;
271             }
272         }
273         return false;
274     }
275 
getTopState()276     public ActivityState getTopState() {
277         Utils.assertTrue(!mStack.isEmpty());
278         return mStack.peek().activityState;
279     }
280 
281     private static class StateEntry {
282         public Bundle data;
283         public ActivityState activityState;
284 
StateEntry(Bundle data, ActivityState state)285         public StateEntry(Bundle data, ActivityState state) {
286             this.data = data;
287             this.activityState = state;
288         }
289     }
290 }
291