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.ActionBar;
20import android.app.Activity;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.res.Configuration;
27import android.os.BatteryManager;
28import android.os.Bundle;
29import android.provider.Settings;
30import android.provider.Settings.SettingNotFoundException;
31import android.view.Menu;
32import android.view.MenuInflater;
33import android.view.MenuItem;
34import android.view.Window;
35import android.view.WindowManager;
36
37import com.android.gallery3d.R;
38import com.android.gallery3d.anim.StateTransitionAnimation;
39import com.android.gallery3d.ui.GLView;
40import com.android.gallery3d.ui.PreparePageFadeoutTexture;
41import com.android.gallery3d.ui.RawTexture;
42import com.android.gallery3d.util.GalleryUtils;
43
44abstract public class ActivityState {
45    protected static final int FLAG_HIDE_ACTION_BAR = 1;
46    protected static final int FLAG_HIDE_STATUS_BAR = 2;
47    protected static final int FLAG_SCREEN_ON_WHEN_PLUGGED = 4;
48    protected static final int FLAG_SCREEN_ON_ALWAYS = 8;
49    protected static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 16;
50    protected static final int FLAG_SHOW_WHEN_LOCKED = 32;
51
52    protected AbstractGalleryActivity mActivity;
53    protected Bundle mData;
54    protected int mFlags;
55
56    protected ResultEntry mReceivedResults;
57    protected ResultEntry mResult;
58
59    protected static class ResultEntry {
60        public int requestCode;
61        public int resultCode = Activity.RESULT_CANCELED;
62        public Intent resultData;
63    }
64
65    protected boolean mHapticsEnabled;
66    private ContentResolver mContentResolver;
67
68    private boolean mDestroyed = false;
69    private boolean mPlugged = false;
70    boolean mIsFinishing = false;
71
72    private static final String KEY_TRANSITION_IN = "transition-in";
73
74    private StateTransitionAnimation.Transition mNextTransition =
75            StateTransitionAnimation.Transition.None;
76    private StateTransitionAnimation mIntroAnimation;
77    private GLView mContentPane;
78
79    protected ActivityState() {
80    }
81
82    protected void setContentPane(GLView content) {
83        mContentPane = content;
84        if (mIntroAnimation != null) {
85            mContentPane.setIntroAnimation(mIntroAnimation);
86            mIntroAnimation = null;
87        }
88        mContentPane.setBackgroundColor(getBackgroundColor());
89        mActivity.getGLRoot().setContentPane(mContentPane);
90    }
91
92    void initialize(AbstractGalleryActivity activity, Bundle data) {
93        mActivity = activity;
94        mData = data;
95        mContentResolver = activity.getAndroidContext().getContentResolver();
96    }
97
98    public Bundle getData() {
99        return mData;
100    }
101
102    protected void onBackPressed() {
103        mActivity.getStateManager().finishState(this);
104    }
105
106    protected void setStateResult(int resultCode, Intent data) {
107        if (mResult == null) return;
108        mResult.resultCode = resultCode;
109        mResult.resultData = data;
110    }
111
112    protected void onConfigurationChanged(Configuration config) {
113    }
114
115    protected void onSaveState(Bundle outState) {
116    }
117
118    protected void onStateResult(int requestCode, int resultCode, Intent data) {
119    }
120
121    protected float[] mBackgroundColor;
122
123    protected int getBackgroundColorId() {
124        return R.color.default_background;
125    }
126
127    protected float[] getBackgroundColor() {
128        return mBackgroundColor;
129    }
130
131    protected void onCreate(Bundle data, Bundle storedState) {
132        mBackgroundColor = GalleryUtils.intColorToFloatARGBArray(
133                mActivity.getResources().getColor(getBackgroundColorId()));
134    }
135
136    protected void clearStateResult() {
137    }
138
139    BroadcastReceiver mPowerIntentReceiver = new BroadcastReceiver() {
140        @Override
141        public void onReceive(Context context, Intent intent) {
142            final String action = intent.getAction();
143            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
144                boolean plugged = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
145
146                if (plugged != mPlugged) {
147                    mPlugged = plugged;
148                    setScreenFlags();
149                }
150            }
151        }
152    };
153
154    private void setScreenFlags() {
155        final Window win = mActivity.getWindow();
156        final WindowManager.LayoutParams params = win.getAttributes();
157        if ((0 != (mFlags & FLAG_SCREEN_ON_ALWAYS)) ||
158                (mPlugged && 0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED))) {
159            params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
160        } else {
161            params.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
162        }
163        if (0 != (mFlags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)) {
164            params.flags |= WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
165        } else {
166            params.flags &= ~WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
167        }
168        if (0 != (mFlags & FLAG_SHOW_WHEN_LOCKED)) {
169            params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
170        } else {
171            params.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
172        }
173        win.setAttributes(params);
174    }
175
176    protected void transitionOnNextPause(Class<? extends ActivityState> outgoing,
177            Class<? extends ActivityState> incoming, StateTransitionAnimation.Transition hint) {
178        if (outgoing == PhotoPage.class && incoming == AlbumPage.class) {
179            mNextTransition = StateTransitionAnimation.Transition.Outgoing;
180        } else if (outgoing == AlbumPage.class && incoming == PhotoPage.class) {
181            mNextTransition = StateTransitionAnimation.Transition.PhotoIncoming;
182        } else {
183            mNextTransition = hint;
184        }
185    }
186
187    protected void onPause() {
188        if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
189            ((Activity) mActivity).unregisterReceiver(mPowerIntentReceiver);
190        }
191        if (mNextTransition != StateTransitionAnimation.Transition.None) {
192            mActivity.getTransitionStore().put(KEY_TRANSITION_IN, mNextTransition);
193            PreparePageFadeoutTexture.prepareFadeOutTexture(mActivity, mContentPane);
194            mNextTransition = StateTransitionAnimation.Transition.None;
195        }
196    }
197
198    // should only be called by StateManager
199    void resume() {
200        AbstractGalleryActivity activity = mActivity;
201        ActionBar actionBar = activity.getActionBar();
202        if (actionBar != null) {
203            if ((mFlags & FLAG_HIDE_ACTION_BAR) != 0) {
204                actionBar.hide();
205            } else {
206                actionBar.show();
207            }
208            int stateCount = mActivity.getStateManager().getStateCount();
209            mActivity.getGalleryActionBar().setDisplayOptions(stateCount > 1, true);
210            // Default behavior, this can be overridden in ActivityState's onResume.
211            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
212        }
213
214        activity.invalidateOptionsMenu();
215
216        setScreenFlags();
217
218        boolean lightsOut = ((mFlags & FLAG_HIDE_STATUS_BAR) != 0);
219        mActivity.getGLRoot().setLightsOutMode(lightsOut);
220
221        ResultEntry entry = mReceivedResults;
222        if (entry != null) {
223            mReceivedResults = null;
224            onStateResult(entry.requestCode, entry.resultCode, entry.resultData);
225        }
226
227        if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
228            // we need to know whether the device is plugged in to do this correctly
229            final IntentFilter filter = new IntentFilter();
230            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
231            activity.registerReceiver(mPowerIntentReceiver, filter);
232        }
233
234        try {
235            mHapticsEnabled = Settings.System.getInt(mContentResolver,
236                    Settings.System.HAPTIC_FEEDBACK_ENABLED) != 0;
237        } catch (SettingNotFoundException e) {
238            mHapticsEnabled = false;
239        }
240
241        onResume();
242
243        // the transition store should be cleared after resume;
244        mActivity.getTransitionStore().clear();
245    }
246
247    // a subclass of ActivityState should override the method to resume itself
248    protected void onResume() {
249        RawTexture fade = mActivity.getTransitionStore().get(
250                PreparePageFadeoutTexture.KEY_FADE_TEXTURE);
251        mNextTransition = mActivity.getTransitionStore().get(
252                KEY_TRANSITION_IN, StateTransitionAnimation.Transition.None);
253        if (mNextTransition != StateTransitionAnimation.Transition.None) {
254            mIntroAnimation = new StateTransitionAnimation(mNextTransition, fade);
255            mNextTransition = StateTransitionAnimation.Transition.None;
256        }
257    }
258
259    protected boolean onCreateActionBar(Menu menu) {
260        // TODO: we should return false if there is no menu to show
261        //       this is a workaround for a bug in system
262        return true;
263    }
264
265    protected boolean onItemSelected(MenuItem item) {
266        return false;
267    }
268
269    protected void onDestroy() {
270        mDestroyed = true;
271    }
272
273    boolean isDestroyed() {
274        return mDestroyed;
275    }
276
277    public boolean isFinishing() {
278        return mIsFinishing;
279    }
280
281    protected MenuInflater getSupportMenuInflater() {
282        return mActivity.getMenuInflater();
283    }
284}
285