blob: f17168901c21e7f7f5330051674eaa89fef5933b [file] [log] [blame]
Owen Lina2fba682011-08-17 22:07:43 +08001/*
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
17package com.android.gallery3d.app;
18
19import com.android.gallery3d.common.Utils;
20
21import android.app.Activity;
22import android.content.Intent;
Owen Lin5f01ca62011-09-09 13:33:44 +080023import android.content.res.Configuration;
Owen Lina2fba682011-08-17 22:07:43 +080024import android.os.Bundle;
25import android.os.Parcelable;
26import android.view.Menu;
27import android.view.MenuItem;
28
29import java.util.Stack;
30
31public 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";
Owen Lin799c8442011-08-26 20:45:35 +080040 private static final String KEY_LAUNCH_GALLERY_ON_TOP = "launch-gallery-on-top";
Owen Lina2fba682011-08-17 22:07:43 +080041
42 private GalleryActivity mContext;
43 private Stack<StateEntry> mStack = new Stack<StateEntry>();
44 private ActivityState.ResultEntry mResult;
Owen Lin799c8442011-08-26 20:45:35 +080045 private boolean mLaunchGalleryOnTop = false;
Owen Lina2fba682011-08-17 22:07:43 +080046
47 public StateManager(GalleryActivity context) {
48 mContext = context;
49 }
50
51 public void startState(Class<? extends ActivityState> klass,
52 Bundle data) {
53 Log.v(TAG, "startState " + klass);
54 ActivityState state = null;
55 try {
56 state = klass.newInstance();
57 } catch (Exception e) {
58 throw new AssertionError(e);
59 }
60 if (!mStack.isEmpty()) {
61 ActivityState top = getTopState();
62 if (mIsResumed) top.onPause();
63 }
64 state.initialize(mContext, data);
65
66 mStack.push(new StateEntry(data, state));
67 state.onCreate(data, null);
68 if (mIsResumed) state.resume();
69 }
70
Owen Lin799c8442011-08-26 20:45:35 +080071 public void setLaunchGalleryOnTop(boolean enabled) {
72 mLaunchGalleryOnTop = enabled;
73 }
74
Owen Lina2fba682011-08-17 22:07:43 +080075 public void startStateForResult(Class<? extends ActivityState> klass,
76 int requestCode, Bundle data) {
77 Log.v(TAG, "startStateForResult " + klass + ", " + requestCode);
78 ActivityState state = null;
79 try {
80 state = klass.newInstance();
81 } catch (Exception e) {
82 throw new AssertionError(e);
83 }
84 state.initialize(mContext, data);
85 state.mResult = new ActivityState.ResultEntry();
86 state.mResult.requestCode = requestCode;
87
88 if (!mStack.isEmpty()) {
89 ActivityState as = getTopState();
90 as.mReceivedResults = state.mResult;
91 if (mIsResumed) as.onPause();
92 } else {
93 mResult = state.mResult;
94 }
95
96 mStack.push(new StateEntry(data, state));
97 state.onCreate(data, null);
98 if (mIsResumed) state.resume();
99 }
100
101 public boolean createOptionsMenu(Menu menu) {
102 if (!mStack.isEmpty()) {
103 ((Activity) mContext).setProgressBarIndeterminateVisibility(false);
104 return getTopState().onCreateActionBar(menu);
105 } else {
106 return false;
107 }
108 }
109
Owen Lin5f01ca62011-09-09 13:33:44 +0800110 public void onConfigurationChange(Configuration config) {
111 for (StateEntry entry : mStack) {
112 entry.activityState.onConfigurationChanged(config);
113 }
114 }
115
Owen Lina2fba682011-08-17 22:07:43 +0800116 public void resume() {
117 if (mIsResumed) return;
118 mIsResumed = true;
119 if (!mStack.isEmpty()) getTopState().resume();
120 }
121
122 public void pause() {
123 if (!mIsResumed) return;
124 mIsResumed = false;
125 if (!mStack.isEmpty()) getTopState().onPause();
126 }
127
128 public void notifyActivityResult(int requestCode, int resultCode, Intent data) {
129 getTopState().onStateResult(requestCode, resultCode, data);
130 }
131
132 public int getStateCount() {
133 return mStack.size();
134 }
135
136 public boolean itemSelected(MenuItem item) {
137 if (!mStack.isEmpty()) {
Owen Lin799c8442011-08-26 20:45:35 +0800138 if (item.getItemId() == android.R.id.home) {
139 if (mStack.size() > 1) {
140 getTopState().onBackPressed();
141 } else if (mLaunchGalleryOnTop) {
142 Activity activity = (Activity) mContext;
143 Intent intent = new Intent(activity, Gallery.class)
144 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
145 ((Activity) mContext).startActivity(intent);
146 }
Owen Lina2fba682011-08-17 22:07:43 +0800147 return true;
148 } else {
149 return getTopState().onItemSelected(item);
150 }
151 }
152 return false;
153 }
154
155 public void onBackPressed() {
156 if (!mStack.isEmpty()) {
157 getTopState().onBackPressed();
158 }
159 }
160
161 void finishState(ActivityState state) {
Chih-Chung Chang3cc02702012-01-09 12:41:57 +0800162 Log.v(TAG, "finishState " + state);
Owen Lina2fba682011-08-17 22:07:43 +0800163 if (state != mStack.peek().activityState) {
Hung-ying Tyan9d62da72011-09-30 14:42:50 +0800164 if (state.isDestroyed()) {
165 Log.d(TAG, "The state is already destroyed");
166 return;
167 } else {
168 throw new IllegalArgumentException("The stateview to be finished"
169 + " is not at the top of the stack: " + state + ", "
170 + mStack.peek().activityState);
171 }
Owen Lina2fba682011-08-17 22:07:43 +0800172 }
173
174 // Remove the top state.
175 mStack.pop();
176 if (mIsResumed) state.onPause();
177 mContext.getGLRoot().setContentPane(null);
178 state.onDestroy();
179
180 if (mStack.isEmpty()) {
181 Log.v(TAG, "no more state, finish activity");
182 Activity activity = (Activity) mContext.getAndroidContext();
183 if (mResult != null) {
184 activity.setResult(mResult.resultCode, mResult.resultData);
185 }
186 activity.finish();
187
188 // The finish() request is rejected (only happens under Monkey),
189 // so we start the default page instead.
190 if (!activity.isFinishing()) {
191 Log.v(TAG, "finish() failed, start default page");
192 ((Gallery) mContext).startDefaultPage();
193 }
194 } else {
195 // Restore the immediately previous state
196 ActivityState top = mStack.peek().activityState;
197 if (mIsResumed) top.resume();
198 }
199 }
200
201 void switchState(ActivityState oldState,
202 Class<? extends ActivityState> klass, Bundle data) {
203 Log.v(TAG, "switchState " + oldState + ", " + klass);
204 if (oldState != mStack.peek().activityState) {
205 throw new IllegalArgumentException("The stateview to be finished"
206 + " is not at the top of the stack: " + oldState + ", "
207 + mStack.peek().activityState);
208 }
209 // Remove the top state.
210 mStack.pop();
211 if (mIsResumed) oldState.onPause();
212 oldState.onDestroy();
213
214 // Create new state.
215 ActivityState state = null;
216 try {
217 state = klass.newInstance();
218 } catch (Exception e) {
219 throw new AssertionError(e);
220 }
221 state.initialize(mContext, data);
222 mStack.push(new StateEntry(data, state));
223 state.onCreate(data, null);
224 if (mIsResumed) state.resume();
225 }
226
227 public void destroy() {
228 Log.v(TAG, "destroy");
229 while (!mStack.isEmpty()) {
230 mStack.pop().activityState.onDestroy();
231 }
232 mStack.clear();
233 }
234
235 @SuppressWarnings("unchecked")
236 public void restoreFromState(Bundle inState) {
237 Log.v(TAG, "restoreFromState");
Owen Lin799c8442011-08-26 20:45:35 +0800238 mLaunchGalleryOnTop = inState.getBoolean(KEY_LAUNCH_GALLERY_ON_TOP, false);
Owen Lina2fba682011-08-17 22:07:43 +0800239 Parcelable list[] = inState.getParcelableArray(KEY_MAIN);
Owen Lina2fba682011-08-17 22:07:43 +0800240 for (Parcelable parcelable : list) {
241 Bundle bundle = (Bundle) parcelable;
242 Class<? extends ActivityState> klass =
243 (Class<? extends ActivityState>) bundle.getSerializable(KEY_CLASS);
244
245 Bundle data = bundle.getBundle(KEY_DATA);
246 Bundle state = bundle.getBundle(KEY_STATE);
247
248 ActivityState activityState;
249 try {
250 Log.v(TAG, "restoreFromState " + klass);
251 activityState = klass.newInstance();
252 } catch (Exception e) {
253 throw new AssertionError(e);
254 }
255 activityState.initialize(mContext, data);
256 activityState.onCreate(data, state);
257 mStack.push(new StateEntry(data, activityState));
258 }
259 }
260
261 public void saveState(Bundle outState) {
262 Log.v(TAG, "saveState");
Owen Lina2fba682011-08-17 22:07:43 +0800263
Owen Lin799c8442011-08-26 20:45:35 +0800264 outState.putBoolean(KEY_LAUNCH_GALLERY_ON_TOP, mLaunchGalleryOnTop);
265 Parcelable list[] = new Parcelable[mStack.size()];
Owen Lina2fba682011-08-17 22:07:43 +0800266 int i = 0;
267 for (StateEntry entry : mStack) {
268 Bundle bundle = new Bundle();
269 bundle.putSerializable(KEY_CLASS, entry.activityState.getClass());
270 bundle.putBundle(KEY_DATA, entry.data);
271 Bundle state = new Bundle();
272 entry.activityState.onSaveState(state);
273 bundle.putBundle(KEY_STATE, state);
274 Log.v(TAG, "saveState " + entry.activityState.getClass());
275 list[i++] = bundle;
276 }
277 outState.putParcelableArray(KEY_MAIN, list);
278 }
279
280 public boolean hasStateClass(Class<? extends ActivityState> klass) {
281 for (StateEntry entry : mStack) {
282 if (klass.isInstance(entry.activityState)) {
283 return true;
284 }
285 }
286 return false;
287 }
288
289 public ActivityState getTopState() {
290 Utils.assertTrue(!mStack.isEmpty());
291 return mStack.peek().activityState;
292 }
293
294 private static class StateEntry {
295 public Bundle data;
296 public ActivityState activityState;
297
298 public StateEntry(Bundle data, ActivityState state) {
299 this.data = data;
300 this.activityState = state;
301 }
302 }
303}