• 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 com.android.gallery3d.common.Utils;
20 
21 import android.app.Activity;
22 import android.content.Intent;
23 import android.content.res.Configuration;
24 import android.os.Bundle;
25 import android.os.Parcelable;
26 import android.view.Menu;
27 import android.view.MenuItem;
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     private static final String KEY_LAUNCH_GALLERY_ON_TOP = "launch-gallery-on-top";
41 
42     private GalleryActivity mContext;
43     private Stack<StateEntry> mStack = new Stack<StateEntry>();
44     private ActivityState.ResultEntry mResult;
45     private boolean mLaunchGalleryOnTop = false;
46 
StateManager(GalleryActivity context)47     public StateManager(GalleryActivity context) {
48         mContext = context;
49     }
50 
startState(Class<? extends ActivityState> klass, Bundle data)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 
setLaunchGalleryOnTop(boolean enabled)71     public void setLaunchGalleryOnTop(boolean enabled) {
72         mLaunchGalleryOnTop = enabled;
73     }
74 
startStateForResult(Class<? extends ActivityState> klass, int requestCode, Bundle data)75     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 
createOptionsMenu(Menu menu)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 
onConfigurationChange(Configuration config)110     public void onConfigurationChange(Configuration config) {
111         for (StateEntry entry : mStack) {
112             entry.activityState.onConfigurationChanged(config);
113         }
114     }
115 
resume()116     public void resume() {
117         if (mIsResumed) return;
118         mIsResumed = true;
119         if (!mStack.isEmpty()) getTopState().resume();
120     }
121 
pause()122     public void pause() {
123         if (!mIsResumed) return;
124         mIsResumed = false;
125         if (!mStack.isEmpty()) getTopState().onPause();
126     }
127 
notifyActivityResult(int requestCode, int resultCode, Intent data)128     public void notifyActivityResult(int requestCode, int resultCode, Intent data) {
129         getTopState().onStateResult(requestCode, resultCode, data);
130     }
131 
getStateCount()132     public int getStateCount() {
133         return mStack.size();
134     }
135 
itemSelected(MenuItem item)136     public boolean itemSelected(MenuItem item) {
137         if (!mStack.isEmpty()) {
138             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                 }
147                 return true;
148             } else {
149                 return getTopState().onItemSelected(item);
150             }
151         }
152         return false;
153     }
154 
onBackPressed()155     public void onBackPressed() {
156         if (!mStack.isEmpty()) {
157             getTopState().onBackPressed();
158         }
159     }
160 
finishState(ActivityState state)161     void finishState(ActivityState state) {
162         Log.v(TAG, "finishState " + state.getClass());
163         if (state != mStack.peek().activityState) {
164             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             }
172         }
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 
switchState(ActivityState oldState, Class<? extends ActivityState> klass, Bundle data)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 
destroy()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")
restoreFromState(Bundle inState)236     public void restoreFromState(Bundle inState) {
237         Log.v(TAG, "restoreFromState");
238         mLaunchGalleryOnTop = inState.getBoolean(KEY_LAUNCH_GALLERY_ON_TOP, false);
239         Parcelable list[] = inState.getParcelableArray(KEY_MAIN);
240         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 
saveState(Bundle outState)261     public void saveState(Bundle outState) {
262         Log.v(TAG, "saveState");
263 
264         outState.putBoolean(KEY_LAUNCH_GALLERY_ON_TOP, mLaunchGalleryOnTop);
265         Parcelable list[] = new Parcelable[mStack.size()];
266         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 
hasStateClass(Class<? extends ActivityState> klass)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 
getTopState()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 
StateEntry(Bundle data, ActivityState state)298         public StateEntry(Bundle data, ActivityState state) {
299             this.data = data;
300             this.activityState = state;
301         }
302     }
303 }
304