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