1 package com.cooliris.media;
3 import java.io.IOException;
4 import java.net.URISyntaxException;
5 import java.util.HashMap;
6 import java.util.TimeZone;
8 import android.app.Activity;
9 import android.app.ProgressDialog;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.res.Configuration;
13 import android.graphics.Bitmap;
14 import android.net.Uri;
15 import android.os.Bundle;
16 import android.os.Handler;
17 import android.os.PowerManager;
18 import android.os.PowerManager.WakeLock;
19 import android.provider.MediaStore.Images;
20 import android.util.DisplayMetrics;
21 import android.util.Log;
22 import android.view.KeyEvent;
23 import android.widget.Toast;
24 import android.media.MediaScannerConnection;
26 import com.cooliris.cache.CacheService;
27 import com.cooliris.wallpaper.RandomDataSource;
28 import com.cooliris.wallpaper.Slideshow;
30 public final class Gallery extends Activity {
31 public static final TimeZone CURRENT_TIME_ZONE = TimeZone.getDefault();
32 public static float PIXEL_DENSITY = 0.0f;
33 public static final int CROP_MSG_INTERNAL = 100;
35 private static final String TAG = "Gallery";
36 private static final int CROP_MSG = 10;
37 private RenderView mRenderView = null;
38 private GridLayer mGridLayer;
39 private final Handler mHandler = new Handler();
40 private ReverseGeocoder mReverseGeocoder;
41 private boolean mPause;
42 private MediaScannerConnection mConnection;
43 private WakeLock mWakeLock;
44 private HashMap<String, Boolean> mAccountsEnabled = new HashMap<String, Boolean>();
47 public void onCreate(Bundle savedInstanceState) {
48 super.onCreate(savedInstanceState);
49 final boolean imageManagerHasStorage = ImageManager.quickHasStorage();
50 boolean slideshowIntent = false;
52 Bundle extras = getIntent().getExtras();
54 slideshowIntent = extras.getBoolean("slideshow", false);
57 if (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI)
59 if (!imageManagerHasStorage) {
60 Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
63 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
64 mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow.All");
66 Slideshow slideshow = new Slideshow(this);
67 slideshow.setDataSource(new RandomDataSource());
68 setContentView(slideshow);
72 CacheService.computeDirtySets(this);
73 final boolean isCacheReady = CacheService.isCacheReady(false);
74 if (PIXEL_DENSITY == 0.0f) {
75 DisplayMetrics metrics = new DisplayMetrics();
76 getWindowManager().getDefaultDisplay().getMetrics(metrics);
77 PIXEL_DENSITY = metrics.density;
79 mReverseGeocoder = new ReverseGeocoder(this);
80 mRenderView = new RenderView(this);
81 mGridLayer = new GridLayer(this, (int) (96.0f * PIXEL_DENSITY), (int) (72.0f * PIXEL_DENSITY), new GridLayoutInterface(4),
83 mRenderView.setRootLayer(mGridLayer);
84 setContentView(mRenderView);
86 // Creating the DataSource objects.
87 final PicasaDataSource picasaDataSource = new PicasaDataSource(this);
88 final LocalDataSource localDataSource = new LocalDataSource(this);
89 final ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
91 // Depending upon the intent, we assign the right dataSource.
92 if (!isPickIntent() && !isViewIntent()) {
93 if (imageManagerHasStorage) {
94 mGridLayer.setDataSource(combinedDataSource);
96 mGridLayer.setDataSource(picasaDataSource);
98 if (!imageManagerHasStorage) {
99 Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
100 } else if (!isCacheReady) {
101 Toast.makeText(this, getResources().getString(R.string.loading_new), Toast.LENGTH_LONG).show();
103 } else if (!isViewIntent()) {
104 final Intent intent = getIntent();
105 if (intent != null) {
106 final String type = intent.resolveType(this);
107 boolean includeImages = isImageType(type);
108 boolean includeVideos = isVideoType(type);
109 ((LocalDataSource) localDataSource).setMimeFilter(!includeImages, !includeVideos);
111 if (imageManagerHasStorage) {
112 mGridLayer.setDataSource(combinedDataSource);
114 mGridLayer.setDataSource(picasaDataSource);
117 mGridLayer.setDataSource(localDataSource);
119 mGridLayer.setPickIntent(true);
120 if (!imageManagerHasStorage) {
121 Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
123 Toast.makeText(this, getResources().getString(R.string.pick_prompt), Toast.LENGTH_LONG).show();
127 // View intent for images.
128 Uri uri = getIntent().getData();
129 boolean slideshow = getIntent().getBooleanExtra("slideshow", false);
130 final SingleDataSource singleDataSource = new SingleDataSource(this, uri.toString(), slideshow);
131 final ConcatenatedDataSource singleCombinedDataSource = new ConcatenatedDataSource(singleDataSource, picasaDataSource);
132 mGridLayer.setDataSource(singleCombinedDataSource);
133 mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(uri));
134 if (singleDataSource.isSingleImage()) {
135 mGridLayer.setSingleImage(false);
136 } else if (slideshow) {
137 mGridLayer.setSingleImage(true);
138 mGridLayer.startSlideshow();
141 // We record the set of enabled accounts for picasa.
142 mAccountsEnabled = PicasaDataSource.getAccountStatus(this);
143 Log.i(TAG, "onCreate");
146 public ReverseGeocoder getReverseGeocoder() {
147 return mReverseGeocoder;
150 public Handler getHandler() {
155 public void onRestart() {
160 public void onStart() {
165 public void onResume() {
167 CacheService.computeDirtySets(this);
168 CacheService.startCache(this, false);
169 if (mRenderView != null) {
170 mRenderView.onResume();
173 // We check to see if the authenticated accounts have changed, and
174 // if so, reload the datasource.
175 HashMap<String, Boolean> accountsEnabled = PicasaDataSource.getAccountStatus(this);
176 String[] keys = new String[accountsEnabled.size()];
177 keys = accountsEnabled.keySet().toArray(keys);
178 int numKeys = keys.length;
179 for (int i = 0; i < numKeys; ++i) {
180 String key = keys[i];
181 boolean newValue = accountsEnabled.get(key).booleanValue();
182 boolean oldValue = false;
183 Boolean oldValObj = mAccountsEnabled.get(key);
184 if (oldValObj != null) {
185 oldValue = oldValObj.booleanValue();
187 if (oldValue != newValue) {
188 // Reload the datasource.
189 if (mGridLayer != null)
190 mGridLayer.setDataSource(mGridLayer.getDataSource());
194 mAccountsEnabled = accountsEnabled;
200 public void onPause() {
202 if (mRenderView != null)
203 mRenderView.onPause();
207 public boolean isPaused() {
212 public void onStop() {
214 if (mGridLayer != null)
216 if (mReverseGeocoder != null) {
217 mReverseGeocoder.flushCache();
219 LocalDataSource.sThumbnailCache.flush();
220 LocalDataSource.sThumbnailCacheVideo.flush();
221 PicasaDataSource.sThumbnailCache.flush();
222 CacheService.startCache(this, true);
226 public void onDestroy() {
227 // Force GLThread to exit.
228 setContentView(R.layout.main);
229 if (mGridLayer != null) {
230 DataSource dataSource = mGridLayer.getDataSource();
231 if (dataSource != null) {
232 dataSource.shutdown();
234 mGridLayer.shutdown();
236 if (mWakeLock != null) {
237 if (mWakeLock.isHeld()) {
242 if (mReverseGeocoder != null)
243 mReverseGeocoder.shutdown();
244 if (mRenderView != null) {
245 mRenderView.shutdown();
250 Log.i(TAG, "onDestroy");
254 public void onConfigurationChanged(Configuration newConfig) {
255 super.onConfigurationChanged(newConfig);
256 if (mGridLayer != null) {
257 mGridLayer.markDirty(30);
259 if (mRenderView != null)
260 mRenderView.requestRender();
261 Log.i(TAG, "onConfigurationChanged");
265 public boolean onKeyDown(int keyCode, KeyEvent event) {
266 if (mRenderView != null) {
267 return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
269 return super.onKeyDown(keyCode, event);
273 private boolean isPickIntent() {
274 String action = getIntent().getAction();
275 return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
278 private boolean isViewIntent() {
279 String action = getIntent().getAction();
280 return Intent.ACTION_VIEW.equals(action);
283 private boolean isImageType(String type) {
284 return type.equals("vnd.android.cursor.dir/image") || type.equals("image/*");
287 private boolean isVideoType(String type) {
288 return type.equals("vnd.android.cursor.dir/video") || type.equals("video/*");
292 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
293 switch (requestCode) {
295 if (resultCode == RESULT_OK) {
296 setResult(resultCode, data);
301 case CROP_MSG_INTERNAL: {
302 // We cropped an image, we must try to set the focus of the camera
304 if (resultCode == RESULT_OK) {
305 String contentUri = data.getAction();
306 if (mGridLayer != null) {
307 mGridLayer.focusItem(contentUri);
316 public void onLowMemory() {
317 if (mRenderView != null) {
318 mRenderView.handleLowMemory();
322 public void launchCropperOrFinish(final MediaItem item) {
323 final Bundle myExtras = getIntent().getExtras();
324 String cropValue = myExtras != null ? myExtras.getString("crop") : null;
325 final String contentUri = item.mContentUri;
326 if (cropValue != null) {
327 Bundle newExtras = new Bundle();
328 if (cropValue.equals("circle")) {
329 newExtras.putString("circleCrop", "true");
331 Intent cropIntent = new Intent();
332 cropIntent.setData(Uri.parse(contentUri));
333 cropIntent.setClass(this, CropImage.class);
334 cropIntent.putExtras(newExtras);
335 // Pass through any extras that were passed in.
336 cropIntent.putExtras(myExtras);
337 startActivityForResult(cropIntent, CROP_MSG);
339 if (contentUri.startsWith("http://")) {
340 // This is a http uri, we must save it locally first and
341 // generate a content uri from it.
342 final ProgressDialog dialog = ProgressDialog.show(this, this.getResources().getString(R.string.initializing),
343 getResources().getString(R.string.running_face_detection), true, false);
344 if (contentUri != null) {
345 MediaScannerConnection.MediaScannerConnectionClient client = new MediaScannerConnection.MediaScannerConnectionClient() {
346 public void onMediaScannerConnected() {
347 if (mConnection != null) {
349 final String path = UriTexture.writeHttpDataInDirectory(Gallery.this, contentUri,
350 LocalDataSource.DOWNLOAD_BUCKET_NAME);
352 mConnection.scanFile(path, item.mMimeType);
356 } catch (Exception e) {
362 public void onScanCompleted(String path, Uri uri) {
363 shutdown(uri.toString());
366 public void shutdown(String uri) {
368 performReturn(myExtras, uri.toString());
369 if (mConnection != null) {
370 mConnection.disconnect();
374 MediaScannerConnection connection = new MediaScannerConnection(Gallery.this, client);
375 connection.connect();
376 mConnection = connection;
379 performReturn(myExtras, contentUri);
384 private void performReturn(Bundle myExtras, String contentUri) {
385 Intent result = new Intent(null, Uri.parse(contentUri));
386 if (myExtras != null && myExtras.getBoolean("return-data")) {
387 // The size of a transaction should be below 100K.
388 Bitmap bitmap = null;
390 bitmap = UriTexture.createFromUri(this, contentUri, 1024, 1024, 0, null);
391 } catch (IOException e) {
393 } catch (URISyntaxException e) {
396 if (bitmap != null) {
397 result.putExtra("data", bitmap);
400 setResult(RESULT_OK, result);