/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cooliris.media; import com.cooliris.app.App; import com.cooliris.app.Res; import com.cooliris.cache.CacheService; import com.cooliris.wallpaper.RandomDataSource; import com.cooliris.wallpaper.Slideshow; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.provider.MediaStore.Images; import android.util.Log; import android.view.KeyEvent; import android.widget.Toast; import java.util.HashMap; public final class Gallery extends Activity { public static final String REVIEW_ACTION = "com.cooliris.media.action.REVIEW"; private static final String TAG = "Gallery"; private App mApp = null; private RenderView mRenderView = null; private GridLayer mGridLayer; private WakeLock mWakeLock; private HashMap<String, Boolean> mAccountsEnabled = new HashMap<String, Boolean>(); private boolean mDockSlideshow = false; private int mNumRetries; private boolean mImageManagerHasStorageAfterDelay = false; private HandlerThread mPicasaAccountThread = new HandlerThread("PicasaAccountMonitor"); private Handler mPicasaHandler = null; private static final int GET_PICASA_ACCOUNT_STATUS = 1; private static final int UPDATE_PICASA_ACCOUNT_STATUS = 2; private static final int CHECK_STORAGE = 0; private static final int HANDLE_INTENT = 1; private static final int NUM_STORAGE_CHECKS = 25; private final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case CHECK_STORAGE: checkStorage(); break; case HANDLE_INTENT: initializeDataSource(); break; } } }; private void checkStorage() { mNumRetries++; mImageManagerHasStorageAfterDelay = ImageManager.hasStorage(); if (!mImageManagerHasStorageAfterDelay && mNumRetries < NUM_STORAGE_CHECKS) { if (mNumRetries == 1) { int res; if (Environment.isExternalStorageRemovable()) { res = Res.string.no_sd_card; } else { res = Res.string.no_usb_storage; } mApp.showToast(getResources().getString(res), Toast.LENGTH_LONG); } handler.sendEmptyMessageDelayed(CHECK_STORAGE, 200); } else { handler.sendEmptyMessage(HANDLE_INTENT); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApp = new App(Gallery.this); final boolean imageManagerHasStorage = ImageManager.hasStorage(); boolean slideshowIntent = false; if (isViewIntent()) { Bundle extras = getIntent().getExtras(); if (extras != null) { slideshowIntent = extras.getBoolean("slideshow", false); } } if (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI) && slideshowIntent) { if (!imageManagerHasStorage) { int res; if (Environment.isExternalStorageRemovable()) { res = Res.string.no_sd_card; } else { res = Res.string.no_usb_storage; } Toast.makeText(this, getResources().getString(res), Toast.LENGTH_LONG).show(); finish(); } else { Slideshow slideshow = new Slideshow(this); slideshow.setDataSource(new RandomDataSource()); setContentView(slideshow); mDockSlideshow = true; } return; } mRenderView = new RenderView(this); mGridLayer = new GridLayer(this, (int) (96.0f * App.PIXEL_DENSITY), (int) (72.0f * App.PIXEL_DENSITY), new GridLayoutInterface(4), mRenderView); mRenderView.setRootLayer(mGridLayer); setContentView(mRenderView); mPicasaAccountThread.start(); mPicasaHandler = new Handler(mPicasaAccountThread.getLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case GET_PICASA_ACCOUNT_STATUS: mAccountsEnabled = PicasaDataSource.getAccountStatus(Gallery.this); break; case UPDATE_PICASA_ACCOUNT_STATUS: updatePicasaAccountStatus(); break; } } }; sendInitialMessage(); Log.i(TAG, "onCreate"); } private void sendInitialMessage() { mNumRetries = 0; Message checkStorage = new Message(); checkStorage.what = CHECK_STORAGE; handler.sendMessage(checkStorage); } @Override protected void onNewIntent(Intent intent) { setIntent(intent); handler.removeMessages(CHECK_STORAGE); handler.removeMessages(HANDLE_INTENT); sendInitialMessage(); } @Override public void onRestart() { super.onRestart(); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); if (mDockSlideshow) { if (mWakeLock != null) { if (mWakeLock.isHeld()) { mWakeLock.release(); } } PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow.All"); mWakeLock.acquire(); return; } if (mRenderView != null) { mRenderView.onResume(); } if (mApp.isPaused()) { if (mPicasaHandler != null) { mPicasaHandler.removeMessages(GET_PICASA_ACCOUNT_STATUS); mPicasaHandler.sendEmptyMessage(UPDATE_PICASA_ACCOUNT_STATUS); } mApp.onResume(); } } void updatePicasaAccountStatus() { // We check to see if the authenticated accounts have // changed, if so, reload the datasource. // TODO: This should be done in PicasaDataFeed if (mGridLayer != null) { HashMap<String, Boolean> accountsEnabled = PicasaDataSource.getAccountStatus(this); if (!accountsEnabled.equals(mAccountsEnabled)) { mGridLayer.setDataSource(mGridLayer.getDataSource()); mAccountsEnabled = accountsEnabled; } } } @Override public void onPause() { super.onPause(); if (mRenderView != null) mRenderView.onPause(); if (mWakeLock != null) { if (mWakeLock.isHeld()) { mWakeLock.release(); } mWakeLock = null; } LocalDataSource.sThumbnailCache.flush(); LocalDataSource.sThumbnailCacheVideo.flush(); PicasaDataSource.sThumbnailCache.flush(); if (mPicasaHandler != null) { mPicasaHandler.removeMessages(GET_PICASA_ACCOUNT_STATUS); mPicasaHandler.removeMessages(UPDATE_PICASA_ACCOUNT_STATUS); } mApp.onPause(); } @Override public void onStop() { super.onStop(); if (mGridLayer != null) mGridLayer.stop(); // Start the thumbnailer. CacheService.startCache(this, true); } @Override public void onDestroy() { // Force GLThread to exit. setContentView(Res.layout.main); // Remove any post messages. handler.removeMessages(CHECK_STORAGE); handler.removeMessages(HANDLE_INTENT); mPicasaAccountThread.quit(); mPicasaAccountThread = null; mPicasaHandler = null; if (mGridLayer != null) { DataSource dataSource = mGridLayer.getDataSource(); if (dataSource != null) { dataSource.shutdown(); } mGridLayer.shutdown(); } if (mRenderView != null) { mRenderView.shutdown(); mRenderView = null; } mGridLayer = null; mApp.shutdown(); super.onDestroy(); Log.i(TAG, "onDestroy"); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (mGridLayer != null) { mGridLayer.markDirty(30); } if (mRenderView != null) mRenderView.requestRender(); Log.i(TAG, "onConfigurationChanged"); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mRenderView != null) { return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); } else { return super.onKeyDown(keyCode, event); } } private boolean isPickIntent() { String action = getIntent().getAction(); return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)); } private boolean isViewIntent() { String action = getIntent().getAction(); return Intent.ACTION_VIEW.equals(action); } private boolean isReviewIntent() { String action = getIntent().getAction(); return REVIEW_ACTION.equals(action); } private boolean isImageType(String type) { return type.contains("*/") || type.equals("vnd.android.cursor.dir/image") || type.equals("image/*"); } private boolean isVideoType(String type) { return type.contains("*/") || type.equals("vnd.android.cursor.dir/video") || type.equals("video/*"); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case CropImage.CROP_MSG: { if (resultCode == RESULT_OK) { setResult(resultCode, data); finish(); } break; } case CropImage.CROP_MSG_INTERNAL: { // We cropped an image, we must try to set the focus of the camera // to that image. if (resultCode == RESULT_OK) { String contentUri = data.getAction(); if (mGridLayer != null && contentUri != null) { mGridLayer.focusItem(contentUri); } } break; } } } @Override public void onLowMemory() { if (mRenderView != null) { mRenderView.handleLowMemory(); } } private void initializeDataSource() { final boolean hasStorage = mImageManagerHasStorageAfterDelay; // Creating the DataSource objects. final PicasaDataSource picasaDataSource = new PicasaDataSource(Gallery.this); final LocalDataSource localDataSource = new LocalDataSource(Gallery.this, LocalDataSource.URI_ALL_MEDIA, false); final ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource); // Depending upon the intent, we assign the right dataSource. if (!isPickIntent() && !isViewIntent() && !isReviewIntent()) { localDataSource.setMimeFilter(true, true); if (hasStorage) { mGridLayer.setDataSource(combinedDataSource); } else { mGridLayer.setDataSource(picasaDataSource); } } else if (isPickIntent()) { final Intent intent = getIntent(); if (intent != null) { String type = intent.resolveType(Gallery.this); if (type == null) { // By default, we include images type = "image/*"; } boolean includeImages = isImageType(type); boolean includeVideos = isVideoType(type); localDataSource.setMimeFilter(includeImages, includeVideos); if (includeImages) { if (hasStorage) { mGridLayer.setDataSource(combinedDataSource); } else { mGridLayer.setDataSource(picasaDataSource); } } else { mGridLayer.setDataSource(localDataSource); } mGridLayer.setPickIntent(true); if (hasStorage) { mApp.showToast(getResources().getString(Res.string.pick_prompt), Toast.LENGTH_LONG); } } } else { // view intent for images and review intent for images and videos final Intent intent = getIntent(); Uri uri = intent.getData(); boolean slideshow = intent.getBooleanExtra("slideshow", false); final LocalDataSource singleDataSource = new LocalDataSource(Gallery.this, uri.toString(), true); // Display both image and video. singleDataSource.setMimeFilter(true, true); if (hasStorage) { ConcatenatedDataSource singleCombinedDataSource = new ConcatenatedDataSource(singleDataSource, picasaDataSource); mGridLayer.setDataSource(singleCombinedDataSource); } else { mGridLayer.setDataSource(picasaDataSource); } mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(getContentResolver(), uri)); if (isReviewIntent()) { mGridLayer.setEnterSelectionMode(true); } if (singleDataSource.isSingleImage()) { mGridLayer.setSingleImage(false); } else if (slideshow) { mGridLayer.setSingleImage(true); mGridLayer.startSlideshow(); } } // We record the set of enabled accounts for picasa. mPicasaHandler.sendEmptyMessage(GET_PICASA_ACCOUNT_STATUS); } }