1/*
2 * Copyright (C) 2009 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.Dialog;
20import android.content.ContentResolver;
21import android.content.DialogInterface;
22import android.content.DialogInterface.OnCancelListener;
23import android.content.Intent;
24import android.net.Uri;
25import android.os.Bundle;
26import android.view.InputDevice;
27import android.view.MotionEvent;
28import android.view.View;
29import android.view.Window;
30import android.view.WindowManager;
31import android.widget.Toast;
32
33import com.android.gallery3d.R;
34import com.android.gallery3d.common.Utils;
35import com.android.gallery3d.data.DataManager;
36import com.android.gallery3d.data.MediaItem;
37import com.android.gallery3d.data.MediaSet;
38import com.android.gallery3d.data.Path;
39import com.android.gallery3d.picasasource.PicasaSource;
40import com.android.gallery3d.util.GalleryUtils;
41
42public final class GalleryActivity extends AbstractGalleryActivity implements OnCancelListener {
43    public static final String EXTRA_SLIDESHOW = "slideshow";
44    public static final String EXTRA_DREAM = "dream";
45    public static final String EXTRA_CROP = "crop";
46
47    public static final String ACTION_REVIEW = "com.android.camera.action.REVIEW";
48    public static final String KEY_GET_CONTENT = "get-content";
49    public static final String KEY_GET_ALBUM = "get-album";
50    public static final String KEY_TYPE_BITS = "type-bits";
51    public static final String KEY_MEDIA_TYPES = "mediaTypes";
52    public static final String KEY_DISMISS_KEYGUARD = "dismiss-keyguard";
53
54    private static final String TAG = "GalleryActivity";
55    private Dialog mVersionCheckDialog;
56
57    @Override
58    protected void onCreate(Bundle savedInstanceState) {
59        super.onCreate(savedInstanceState);
60        requestWindowFeature(Window.FEATURE_ACTION_BAR);
61        requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
62
63        if (getIntent().getBooleanExtra(KEY_DISMISS_KEYGUARD, false)) {
64            getWindow().addFlags(
65                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
66        }
67
68        setContentView(R.layout.main);
69
70        if (savedInstanceState != null) {
71            getStateManager().restoreFromState(savedInstanceState);
72        } else {
73            initializeByIntent();
74        }
75    }
76
77    private void initializeByIntent() {
78        Intent intent = getIntent();
79        String action = intent.getAction();
80
81        if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) {
82            startGetContent(intent);
83        } else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) {
84            // We do NOT really support the PICK intent. Handle it as
85            // the GET_CONTENT. However, we need to translate the type
86            // in the intent here.
87            Log.w(TAG, "action PICK is not supported");
88            String type = Utils.ensureNotNull(intent.getType());
89            if (type.startsWith("vnd.android.cursor.dir/")) {
90                if (type.endsWith("/image")) intent.setType("image/*");
91                if (type.endsWith("/video")) intent.setType("video/*");
92            }
93            startGetContent(intent);
94        } else if (Intent.ACTION_VIEW.equalsIgnoreCase(action)
95                || ACTION_REVIEW.equalsIgnoreCase(action)){
96            startViewAction(intent);
97        } else {
98            startDefaultPage();
99        }
100    }
101
102    public void startDefaultPage() {
103        PicasaSource.showSignInReminder(this);
104        Bundle data = new Bundle();
105        data.putString(AlbumSetPage.KEY_MEDIA_PATH,
106                getDataManager().getTopSetPath(DataManager.INCLUDE_ALL));
107        getStateManager().startState(AlbumSetPage.class, data);
108        mVersionCheckDialog = PicasaSource.getVersionCheckDialog(this);
109        if (mVersionCheckDialog != null) {
110            mVersionCheckDialog.setOnCancelListener(this);
111        }
112    }
113
114    private void startGetContent(Intent intent) {
115        Bundle data = intent.getExtras() != null
116                ? new Bundle(intent.getExtras())
117                : new Bundle();
118        data.putBoolean(KEY_GET_CONTENT, true);
119        int typeBits = GalleryUtils.determineTypeBits(this, intent);
120        data.putInt(KEY_TYPE_BITS, typeBits);
121        data.putString(AlbumSetPage.KEY_MEDIA_PATH,
122                getDataManager().getTopSetPath(typeBits));
123        getStateManager().startState(AlbumSetPage.class, data);
124    }
125
126    private String getContentType(Intent intent) {
127        String type = intent.getType();
128        if (type != null) {
129            return GalleryUtils.MIME_TYPE_PANORAMA360.equals(type)
130                ? MediaItem.MIME_TYPE_JPEG : type;
131        }
132
133        Uri uri = intent.getData();
134        try {
135            return getContentResolver().getType(uri);
136        } catch (Throwable t) {
137            Log.w(TAG, "get type fail", t);
138            return null;
139        }
140    }
141
142    private void startViewAction(Intent intent) {
143        Boolean slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false);
144        if (slideshow) {
145            getActionBar().hide();
146            DataManager manager = getDataManager();
147            Path path = manager.findPathByUri(intent.getData(), intent.getType());
148            if (path == null || manager.getMediaObject(path)
149                    instanceof MediaItem) {
150                path = Path.fromString(
151                        manager.getTopSetPath(DataManager.INCLUDE_IMAGE));
152            }
153            Bundle data = new Bundle();
154            data.putString(SlideshowPage.KEY_SET_PATH, path.toString());
155            data.putBoolean(SlideshowPage.KEY_RANDOM_ORDER, true);
156            data.putBoolean(SlideshowPage.KEY_REPEAT, true);
157            if (intent.getBooleanExtra(EXTRA_DREAM, false)) {
158                data.putBoolean(SlideshowPage.KEY_DREAM, true);
159            }
160            getStateManager().startState(SlideshowPage.class, data);
161        } else {
162            Bundle data = new Bundle();
163            DataManager dm = getDataManager();
164            Uri uri = intent.getData();
165            String contentType = getContentType(intent);
166            if (contentType == null) {
167                Toast.makeText(this,
168                        R.string.no_such_item, Toast.LENGTH_LONG).show();
169                finish();
170                return;
171            }
172            if (uri == null) {
173                int typeBits = GalleryUtils.determineTypeBits(this, intent);
174                data.putInt(KEY_TYPE_BITS, typeBits);
175                data.putString(AlbumSetPage.KEY_MEDIA_PATH,
176                        getDataManager().getTopSetPath(typeBits));
177                getStateManager().startState(AlbumSetPage.class, data);
178            } else if (contentType.startsWith(
179                    ContentResolver.CURSOR_DIR_BASE_TYPE)) {
180                int mediaType = intent.getIntExtra(KEY_MEDIA_TYPES, 0);
181                if (mediaType != 0) {
182                    uri = uri.buildUpon().appendQueryParameter(
183                            KEY_MEDIA_TYPES, String.valueOf(mediaType))
184                            .build();
185                }
186                Path setPath = dm.findPathByUri(uri, null);
187                MediaSet mediaSet = null;
188                if (setPath != null) {
189                    mediaSet = (MediaSet) dm.getMediaObject(setPath);
190                }
191                if (mediaSet != null) {
192                    if (mediaSet.isLeafAlbum()) {
193                        data.putString(AlbumPage.KEY_MEDIA_PATH, setPath.toString());
194                        data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH,
195                                dm.getTopSetPath(DataManager.INCLUDE_ALL));
196                        getStateManager().startState(AlbumPage.class, data);
197                    } else {
198                        data.putString(AlbumSetPage.KEY_MEDIA_PATH, setPath.toString());
199                        getStateManager().startState(AlbumSetPage.class, data);
200                    }
201                } else {
202                    startDefaultPage();
203                }
204            } else {
205                Path itemPath = dm.findPathByUri(uri, contentType);
206                Path albumPath = dm.getDefaultSetOf(itemPath);
207
208                data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, itemPath.toString());
209                data.putBoolean(PhotoPage.KEY_READONLY, true);
210
211                // TODO: Make the parameter "SingleItemOnly" public so other
212                //       activities can reference it.
213                boolean singleItemOnly = (albumPath == null)
214                        || intent.getBooleanExtra("SingleItemOnly", false);
215                if (!singleItemOnly) {
216                    data.putString(PhotoPage.KEY_MEDIA_SET_PATH, albumPath.toString());
217                    // when FLAG_ACTIVITY_NEW_TASK is set, (e.g. when intent is fired
218                    // from notification), back button should behave the same as up button
219                    // rather than taking users back to the home screen
220                    if (intent.getBooleanExtra(PhotoPage.KEY_TREAT_BACK_AS_UP, false)
221                            || ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0)) {
222                        data.putBoolean(PhotoPage.KEY_TREAT_BACK_AS_UP, true);
223                    }
224                }
225
226                getStateManager().startState(SinglePhotoPage.class, data);
227            }
228        }
229    }
230
231    @Override
232    protected void onResume() {
233        Utils.assertTrue(getStateManager().getStateCount() > 0);
234        super.onResume();
235        if (mVersionCheckDialog != null) {
236            mVersionCheckDialog.show();
237        }
238    }
239
240    @Override
241    protected void onPause() {
242        super.onPause();
243        if (mVersionCheckDialog != null) {
244            mVersionCheckDialog.dismiss();
245        }
246    }
247
248    @Override
249    public void onCancel(DialogInterface dialog) {
250        if (dialog == mVersionCheckDialog) {
251            mVersionCheckDialog = null;
252        }
253    }
254
255    @Override
256    public boolean onGenericMotionEvent(MotionEvent event) {
257        final boolean isTouchPad = (event.getSource()
258                & InputDevice.SOURCE_CLASS_POSITION) != 0;
259        if (isTouchPad) {
260            float maxX = event.getDevice().getMotionRange(MotionEvent.AXIS_X).getMax();
261            float maxY = event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax();
262            View decor = getWindow().getDecorView();
263            float scaleX = decor.getWidth() / maxX;
264            float scaleY = decor.getHeight() / maxY;
265            float x = event.getX() * scaleX;
266            //x = decor.getWidth() - x; // invert x
267            float y = event.getY() * scaleY;
268            //y = decor.getHeight() - y; // invert y
269            MotionEvent touchEvent = MotionEvent.obtain(event.getDownTime(),
270                    event.getEventTime(), event.getAction(), x, y, event.getMetaState());
271            return dispatchTouchEvent(touchEvent);
272        }
273        return super.onGenericMotionEvent(event);
274    }
275}
276