StateManager.java revision 4b69c5f52e8ef3209bc0b6889c4a6355614607ca
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 17package com.android.gallery3d.app; 18 19import android.app.Activity; 20import android.content.Intent; 21import android.content.res.Configuration; 22import android.os.Bundle; 23import android.os.Parcelable; 24import android.view.Menu; 25import android.view.MenuItem; 26 27import com.android.gallery3d.common.Utils; 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"; 40 41 private GalleryActivity mContext; 42 private Stack<StateEntry> mStack = new Stack<StateEntry>(); 43 private ActivityState.ResultEntry mResult; 44 45 public StateManager(GalleryActivity context) { 46 mContext = context; 47 } 48 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 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 95 public boolean createOptionsMenu(Menu menu) { 96 if (mStack.isEmpty()) { 97 return false; 98 } else { 99 return getTopState().onCreateActionBar(menu); 100 } 101 } 102 103 public void onConfigurationChange(Configuration config) { 104 for (StateEntry entry : mStack) { 105 entry.activityState.onConfigurationChanged(config); 106 } 107 } 108 109 public void resume() { 110 if (mIsResumed) return; 111 mIsResumed = true; 112 if (!mStack.isEmpty()) getTopState().resume(); 113 } 114 115 public void pause() { 116 if (!mIsResumed) return; 117 mIsResumed = false; 118 if (!mStack.isEmpty()) getTopState().onPause(); 119 } 120 121 public void notifyActivityResult(int requestCode, int resultCode, Intent data) { 122 getTopState().onStateResult(requestCode, resultCode, data); 123 } 124 125 public int getStateCount() { 126 return mStack.size(); 127 } 128 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 142 public void onBackPressed() { 143 if (!mStack.isEmpty()) { 144 getTopState().onBackPressed(); 145 } 146 } 147 148 void finishState(ActivityState state) { 149 Log.v(TAG, "finishState " + state); 150 if (state != mStack.peek().activityState) { 151 if (state.isDestroyed()) { 152 Log.d(TAG, "The state is already destroyed"); 153 return; 154 } else { 155 throw new IllegalArgumentException("The stateview to be finished" 156 + " is not at the top of the stack: " + state + ", " 157 + mStack.peek().activityState); 158 } 159 } 160 161 // Remove the top state. 162 mStack.pop(); 163 if (mIsResumed) state.onPause(); 164 mContext.getGLRoot().setContentPane(null); 165 state.onDestroy(); 166 167 if (mStack.isEmpty()) { 168 Log.v(TAG, "no more state, finish activity"); 169 Activity activity = (Activity) mContext.getAndroidContext(); 170 if (mResult != null) { 171 activity.setResult(mResult.resultCode, mResult.resultData); 172 } 173 activity.finish(); 174 175 // The finish() request is rejected (only happens under Monkey), 176 // so we start the default page instead. 177 if (!activity.isFinishing()) { 178 Log.v(TAG, "finish() failed, start default page"); 179 ((Gallery) mContext).startDefaultPage(); 180 } 181 } else { 182 // Restore the immediately previous state 183 ActivityState top = mStack.peek().activityState; 184 if (mIsResumed) top.resume(); 185 } 186 } 187 188 void switchState(ActivityState oldState, 189 Class<? extends ActivityState> klass, Bundle data) { 190 Log.v(TAG, "switchState " + oldState + ", " + klass); 191 if (oldState != mStack.peek().activityState) { 192 throw new IllegalArgumentException("The stateview to be finished" 193 + " is not at the top of the stack: " + oldState + ", " 194 + mStack.peek().activityState); 195 } 196 // Remove the top state. 197 mStack.pop(); 198 if (mIsResumed) oldState.onPause(); 199 oldState.onDestroy(); 200 201 // Create new state. 202 ActivityState state = null; 203 try { 204 state = klass.newInstance(); 205 } catch (Exception e) { 206 throw new AssertionError(e); 207 } 208 state.initialize(mContext, data); 209 mStack.push(new StateEntry(data, state)); 210 state.onCreate(data, null); 211 if (mIsResumed) state.resume(); 212 } 213 214 public void destroy() { 215 Log.v(TAG, "destroy"); 216 while (!mStack.isEmpty()) { 217 mStack.pop().activityState.onDestroy(); 218 } 219 mStack.clear(); 220 } 221 222 @SuppressWarnings("unchecked") 223 public void restoreFromState(Bundle inState) { 224 Log.v(TAG, "restoreFromState"); 225 Parcelable list[] = inState.getParcelableArray(KEY_MAIN); 226 for (Parcelable parcelable : list) { 227 Bundle bundle = (Bundle) parcelable; 228 Class<? extends ActivityState> klass = 229 (Class<? extends ActivityState>) bundle.getSerializable(KEY_CLASS); 230 231 Bundle data = bundle.getBundle(KEY_DATA); 232 Bundle state = bundle.getBundle(KEY_STATE); 233 234 ActivityState activityState; 235 try { 236 Log.v(TAG, "restoreFromState " + klass); 237 activityState = klass.newInstance(); 238 } catch (Exception e) { 239 throw new AssertionError(e); 240 } 241 activityState.initialize(mContext, data); 242 activityState.onCreate(data, state); 243 mStack.push(new StateEntry(data, activityState)); 244 } 245 } 246 247 public void saveState(Bundle outState) { 248 Log.v(TAG, "saveState"); 249 250 Parcelable list[] = new Parcelable[mStack.size()]; 251 int i = 0; 252 for (StateEntry entry : mStack) { 253 Bundle bundle = new Bundle(); 254 bundle.putSerializable(KEY_CLASS, entry.activityState.getClass()); 255 bundle.putBundle(KEY_DATA, entry.data); 256 Bundle state = new Bundle(); 257 entry.activityState.onSaveState(state); 258 bundle.putBundle(KEY_STATE, state); 259 Log.v(TAG, "saveState " + entry.activityState.getClass()); 260 list[i++] = bundle; 261 } 262 outState.putParcelableArray(KEY_MAIN, list); 263 } 264 265 public boolean hasStateClass(Class<? extends ActivityState> klass) { 266 for (StateEntry entry : mStack) { 267 if (klass.isInstance(entry.activityState)) { 268 return true; 269 } 270 } 271 return false; 272 } 273 274 public ActivityState getTopState() { 275 Utils.assertTrue(!mStack.isEmpty()); 276 return mStack.peek().activityState; 277 } 278 279 private static class StateEntry { 280 public Bundle data; 281 public ActivityState activityState; 282 283 public StateEntry(Bundle data, ActivityState state) { 284 this.data = data; 285 this.activityState = state; 286 } 287 } 288} 289