Home | History | Annotate | Download | only in app
      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 
     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 
     71     public void setLaunchGalleryOnTop(boolean enabled) {
     72         mLaunchGalleryOnTop = enabled;
     73     }
     74 
     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 
    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 
    110     public void onConfigurationChange(Configuration config) {
    111         for (StateEntry entry : mStack) {
    112             entry.activityState.onConfigurationChanged(config);
    113         }
    114     }
    115 
    116     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()) {
    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 
    155     public void onBackPressed() {
    156         if (!mStack.isEmpty()) {
    157             getTopState().onBackPressed();
    158         }
    159     }
    160 
    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 
    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");
    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 
    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 
    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 }
    304