1666ea1b28a76aeba74744148b15099254d918671Owen Lin/*
2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2007 The Android Open Source Project
3666ea1b28a76aeba74744148b15099254d918671Owen Lin *
4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License.
6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at
7666ea1b28a76aeba74744148b15099254d918671Owen Lin *
8666ea1b28a76aeba74744148b15099254d918671Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9666ea1b28a76aeba74744148b15099254d918671Owen Lin *
10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software
11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and
14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License.
15666ea1b28a76aeba74744148b15099254d918671Owen Lin */
16666ea1b28a76aeba74744148b15099254d918671Owen Lin
17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera;
18666ea1b28a76aeba74744148b15099254d918671Owen Lin
19d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Linimport com.android.gallery.R;
20d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Lin
21666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage;
22666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImageList;
23666ea1b28a76aeba74744148b15099254d918671Owen Lin
24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.Activity;
25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.Dialog;
26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.ProgressDialog;
27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.BroadcastReceiver;
28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver;
29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Context;
30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Intent;
31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.IntentFilter;
32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.res.Resources;
33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.database.ContentObserver;
34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap;
35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Canvas;
36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix;
37666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Paint;
38666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PorterDuff;
39666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PorterDuffXfermode;
40666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Rect;
41666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.drawable.Drawable;
42666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri;
43666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Bundle;
44666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Environment;
45666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler;
46666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.StatFs;
47666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore;
48666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore.Images;
49666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log;
50666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.ContextMenu;
51666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.LayoutInflater;
52666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.Menu;
53666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.MenuItem;
54666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View;
55666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.ViewGroup;
56666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.ContextMenu.ContextMenuInfo;
57666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.MenuItem.OnMenuItemClickListener;
58666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.AdapterView;
59666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.BaseAdapter;
60666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.GridView;
61666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.TextView;
62666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.Toast;
63666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.AdapterView.AdapterContextMenuInfo;
64666ea1b28a76aeba74744148b15099254d918671Owen Lin
65666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.ArrayList;
66666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.HashMap;
67666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.Map;
68666ea1b28a76aeba74744148b15099254d918671Owen Lin
69666ea1b28a76aeba74744148b15099254d918671Owen Lin/**
70666ea1b28a76aeba74744148b15099254d918671Owen Lin * The GalleryPicker activity.
71666ea1b28a76aeba74744148b15099254d918671Owen Lin */
728aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Linpublic class GalleryPicker extends NoSearchActivity {
73666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String TAG = "GalleryPicker";
74666ea1b28a76aeba74744148b15099254d918671Owen Lin
75666ea1b28a76aeba74744148b15099254d918671Owen Lin    Handler mHandler = new Handler();  // handler for the main thread
76666ea1b28a76aeba74744148b15099254d918671Owen Lin    Thread mWorkerThread;
77666ea1b28a76aeba74744148b15099254d918671Owen Lin    BroadcastReceiver mReceiver;
78666ea1b28a76aeba74744148b15099254d918671Owen Lin    ContentObserver mDbObserver;
79666ea1b28a76aeba74744148b15099254d918671Owen Lin    GridView mGridView;
80666ea1b28a76aeba74744148b15099254d918671Owen Lin    GalleryPickerAdapter mAdapter;  // mAdapter is only accessed in main thread.
81666ea1b28a76aeba74744148b15099254d918671Owen Lin    boolean mScanning;
82666ea1b28a76aeba74744148b15099254d918671Owen Lin    boolean mUnmounted;
83666ea1b28a76aeba74744148b15099254d918671Owen Lin
84666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
85666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void onCreate(Bundle icicle) {
86666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onCreate(icicle);
87666ea1b28a76aeba74744148b15099254d918671Owen Lin
88666ea1b28a76aeba74744148b15099254d918671Owen Lin        setContentView(R.layout.gallerypicker);
89666ea1b28a76aeba74744148b15099254d918671Owen Lin
90666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGridView = (GridView) findViewById(R.id.albums);
91666ea1b28a76aeba74744148b15099254d918671Owen Lin
92666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
93666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void onItemClick(AdapterView<?> parent, View view,
94666ea1b28a76aeba74744148b15099254d918671Owen Lin                                    int position, long id) {
95666ea1b28a76aeba74744148b15099254d918671Owen Lin                launchFolderGallery(position);
96666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
97666ea1b28a76aeba74744148b15099254d918671Owen Lin        });
98666ea1b28a76aeba74744148b15099254d918671Owen Lin
99666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGridView.setOnCreateContextMenuListener(
100666ea1b28a76aeba74744148b15099254d918671Owen Lin                new View.OnCreateContextMenuListener() {
101666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void onCreateContextMenu(ContextMenu menu, View v,
102666ea1b28a76aeba74744148b15099254d918671Owen Lin                        final ContextMenuInfo menuInfo) {
103666ea1b28a76aeba74744148b15099254d918671Owen Lin                            onCreateGalleryPickerContextMenu(menu, menuInfo);
104666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
105666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
106666ea1b28a76aeba74744148b15099254d918671Owen Lin
107666ea1b28a76aeba74744148b15099254d918671Owen Lin        mReceiver = new BroadcastReceiver() {
108666ea1b28a76aeba74744148b15099254d918671Owen Lin            @Override
109666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void onReceive(Context context, Intent intent) {
110666ea1b28a76aeba74744148b15099254d918671Owen Lin                onReceiveMediaBroadcast(intent);
111666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
112666ea1b28a76aeba74744148b15099254d918671Owen Lin        };
113666ea1b28a76aeba74744148b15099254d918671Owen Lin
114666ea1b28a76aeba74744148b15099254d918671Owen Lin        mDbObserver = new ContentObserver(mHandler) {
115666ea1b28a76aeba74744148b15099254d918671Owen Lin            @Override
116666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void onChange(boolean selfChange) {
117666ea1b28a76aeba74744148b15099254d918671Owen Lin                rebake(false, ImageManager.isMediaScannerScanning(
118666ea1b28a76aeba74744148b15099254d918671Owen Lin                        getContentResolver()));
119666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
120666ea1b28a76aeba74744148b15099254d918671Owen Lin        };
121666ea1b28a76aeba74744148b15099254d918671Owen Lin
122666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageManager.ensureOSXCompatibleFolder();
123666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
124666ea1b28a76aeba74744148b15099254d918671Owen Lin
125666ea1b28a76aeba74744148b15099254d918671Owen Lin    Dialog mMediaScanningDialog;
126666ea1b28a76aeba74744148b15099254d918671Owen Lin
127666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Display a dialog if the storage is being scanned now.
128666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void updateScanningDialog(boolean scanning) {
129666ea1b28a76aeba74744148b15099254d918671Owen Lin        boolean prevScanning = (mMediaScanningDialog != null);
130666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (prevScanning == scanning && mAdapter.mItems.size() == 0) return;
131666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Now we are certain the state is changed.
132666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (prevScanning) {
133666ea1b28a76aeba74744148b15099254d918671Owen Lin            mMediaScanningDialog.cancel();
134666ea1b28a76aeba74744148b15099254d918671Owen Lin            mMediaScanningDialog = null;
135666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (scanning && mAdapter.mItems.size() == 0) {
136666ea1b28a76aeba74744148b15099254d918671Owen Lin            mMediaScanningDialog = ProgressDialog.show(
137666ea1b28a76aeba74744148b15099254d918671Owen Lin                    this,
138666ea1b28a76aeba74744148b15099254d918671Owen Lin                    null,
139666ea1b28a76aeba74744148b15099254d918671Owen Lin                    getResources().getString(R.string.wait),
140666ea1b28a76aeba74744148b15099254d918671Owen Lin                    true,
141666ea1b28a76aeba74744148b15099254d918671Owen Lin                    true);
142666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
143666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
144666ea1b28a76aeba74744148b15099254d918671Owen Lin
145666ea1b28a76aeba74744148b15099254d918671Owen Lin    private View mNoImagesView;
146666ea1b28a76aeba74744148b15099254d918671Owen Lin
147666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Show/Hide the "no images" icon and text. Load resources on demand.
148666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void showNoImagesView() {
149666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mNoImagesView == null) {
150666ea1b28a76aeba74744148b15099254d918671Owen Lin            ViewGroup root  = (ViewGroup) findViewById(R.id.root);
151666ea1b28a76aeba74744148b15099254d918671Owen Lin            getLayoutInflater().inflate(R.layout.gallerypicker_no_images, root);
152666ea1b28a76aeba74744148b15099254d918671Owen Lin            mNoImagesView = findViewById(R.id.no_images);
153666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
154666ea1b28a76aeba74744148b15099254d918671Owen Lin        mNoImagesView.setVisibility(View.VISIBLE);
155666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
156666ea1b28a76aeba74744148b15099254d918671Owen Lin
157666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void hideNoImagesView() {
158666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mNoImagesView != null) {
159666ea1b28a76aeba74744148b15099254d918671Owen Lin            mNoImagesView.setVisibility(View.GONE);
160666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
161666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
162666ea1b28a76aeba74744148b15099254d918671Owen Lin
163666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The storage status is changed, restart the worker or show "no images".
164666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void rebake(boolean unmounted, boolean scanning) {
165666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (unmounted == mUnmounted && scanning == mScanning) return;
166666ea1b28a76aeba74744148b15099254d918671Owen Lin        abortWorker();
167666ea1b28a76aeba74744148b15099254d918671Owen Lin        mUnmounted = unmounted;
168666ea1b28a76aeba74744148b15099254d918671Owen Lin        mScanning = scanning;
169666ea1b28a76aeba74744148b15099254d918671Owen Lin        updateScanningDialog(mScanning);
170666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mUnmounted) {
171666ea1b28a76aeba74744148b15099254d918671Owen Lin            showNoImagesView();
172666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
173666ea1b28a76aeba74744148b15099254d918671Owen Lin            hideNoImagesView();
174666ea1b28a76aeba74744148b15099254d918671Owen Lin            startWorker();
175666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
176666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
177666ea1b28a76aeba74744148b15099254d918671Owen Lin
178666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is called when we receive media-related broadcast.
179666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void onReceiveMediaBroadcast(Intent intent) {
180666ea1b28a76aeba74744148b15099254d918671Owen Lin        String action = intent.getAction();
181666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
182666ea1b28a76aeba74744148b15099254d918671Owen Lin            // SD card available
183666ea1b28a76aeba74744148b15099254d918671Owen Lin            // TODO put up a "please wait" message
184666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
185666ea1b28a76aeba74744148b15099254d918671Owen Lin            // SD card unavailable
186666ea1b28a76aeba74744148b15099254d918671Owen Lin            rebake(true, false);
187666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
188666ea1b28a76aeba74744148b15099254d918671Owen Lin            rebake(false, true);
189666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (action.equals(
190666ea1b28a76aeba74744148b15099254d918671Owen Lin                Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
191666ea1b28a76aeba74744148b15099254d918671Owen Lin            rebake(false, false);
192666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
193666ea1b28a76aeba74744148b15099254d918671Owen Lin            rebake(true, false);
194666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
195666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
196666ea1b28a76aeba74744148b15099254d918671Owen Lin
197666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void launchFolderGallery(int position) {
198666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter.mItems.get(position).launch(this);
199666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
200666ea1b28a76aeba74744148b15099254d918671Owen Lin
201666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void onCreateGalleryPickerContextMenu(ContextMenu menu,
202666ea1b28a76aeba74744148b15099254d918671Owen Lin            final ContextMenuInfo menuInfo) {
203666ea1b28a76aeba74744148b15099254d918671Owen Lin        int position = ((AdapterContextMenuInfo) menuInfo).position;
204666ea1b28a76aeba74744148b15099254d918671Owen Lin        menu.setHeaderTitle(mAdapter.baseTitleForPosition(position));
205666ea1b28a76aeba74744148b15099254d918671Owen Lin        // "Slide Show"
206666ea1b28a76aeba74744148b15099254d918671Owen Lin        if ((mAdapter.getIncludeMediaTypes(position)
207666ea1b28a76aeba74744148b15099254d918671Owen Lin                & ImageManager.INCLUDE_IMAGES) != 0) {
208666ea1b28a76aeba74744148b15099254d918671Owen Lin            menu.add(R.string.slide_show)
209666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .setOnMenuItemClickListener(new OnMenuItemClickListener() {
210666ea1b28a76aeba74744148b15099254d918671Owen Lin                        public boolean onMenuItemClick(MenuItem item) {
211666ea1b28a76aeba74744148b15099254d918671Owen Lin                            return onSlideShowClicked(menuInfo);
212666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
213666ea1b28a76aeba74744148b15099254d918671Owen Lin                    });
214666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
215666ea1b28a76aeba74744148b15099254d918671Owen Lin        // "View"
216666ea1b28a76aeba74744148b15099254d918671Owen Lin        menu.add(R.string.view)
217666ea1b28a76aeba74744148b15099254d918671Owen Lin                .setOnMenuItemClickListener(new OnMenuItemClickListener() {
218666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public boolean onMenuItemClick(MenuItem item) {
219666ea1b28a76aeba74744148b15099254d918671Owen Lin                            return onViewClicked(menuInfo);
220666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
221666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
222666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
223666ea1b28a76aeba74744148b15099254d918671Owen Lin
224666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is called when the user clicks "Slideshow" from the context menu.
225666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean onSlideShowClicked(ContextMenuInfo menuInfo) {
226666ea1b28a76aeba74744148b15099254d918671Owen Lin        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
227666ea1b28a76aeba74744148b15099254d918671Owen Lin        int position = info.position;
228666ea1b28a76aeba74744148b15099254d918671Owen Lin
229666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (position < 0 || position >= mAdapter.mItems.size()) {
230666ea1b28a76aeba74744148b15099254d918671Owen Lin            return true;
231666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
232666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Slide show starts from the first image on the list.
233666ea1b28a76aeba74744148b15099254d918671Owen Lin        Item item = mAdapter.mItems.get(position);
234666ea1b28a76aeba74744148b15099254d918671Owen Lin        Uri targetUri = item.mFirstImageUri;
235666ea1b28a76aeba74744148b15099254d918671Owen Lin
236666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (targetUri != null && item.mBucketId != null) {
237666ea1b28a76aeba74744148b15099254d918671Owen Lin            targetUri = targetUri.buildUpon()
238666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .appendQueryParameter("bucketId", item.mBucketId)
239666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .build();
240666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
241666ea1b28a76aeba74744148b15099254d918671Owen Lin        Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
242666ea1b28a76aeba74744148b15099254d918671Owen Lin        intent.putExtra("slideshow", true);
243666ea1b28a76aeba74744148b15099254d918671Owen Lin        startActivity(intent);
244666ea1b28a76aeba74744148b15099254d918671Owen Lin        return true;
245666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
246666ea1b28a76aeba74744148b15099254d918671Owen Lin
247666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is called when the user clicks "View" from the context menu.
248666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean onViewClicked(ContextMenuInfo menuInfo) {
249666ea1b28a76aeba74744148b15099254d918671Owen Lin        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
250666ea1b28a76aeba74744148b15099254d918671Owen Lin        launchFolderGallery(info.position);
251666ea1b28a76aeba74744148b15099254d918671Owen Lin        return true;
252666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
253666ea1b28a76aeba74744148b15099254d918671Owen Lin
254666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
255666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void onStop() {
256666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onStop();
257666ea1b28a76aeba74744148b15099254d918671Owen Lin
258666ea1b28a76aeba74744148b15099254d918671Owen Lin        abortWorker();
259666ea1b28a76aeba74744148b15099254d918671Owen Lin
260666ea1b28a76aeba74744148b15099254d918671Owen Lin        unregisterReceiver(mReceiver);
261666ea1b28a76aeba74744148b15099254d918671Owen Lin        getContentResolver().unregisterContentObserver(mDbObserver);
262666ea1b28a76aeba74744148b15099254d918671Owen Lin
263666ea1b28a76aeba74744148b15099254d918671Owen Lin        // free up some ram
264666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter = null;
265666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGridView.setAdapter(null);
266666ea1b28a76aeba74744148b15099254d918671Owen Lin        unloadDrawable();
267666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
268666ea1b28a76aeba74744148b15099254d918671Owen Lin
269666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
270666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void onStart() {
271666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onStart();
272666ea1b28a76aeba74744148b15099254d918671Owen Lin
273666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter = new GalleryPickerAdapter(getLayoutInflater());
274666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGridView.setAdapter(mAdapter);
275666ea1b28a76aeba74744148b15099254d918671Owen Lin
276666ea1b28a76aeba74744148b15099254d918671Owen Lin        // install an intent filter to receive SD card related events.
277666ea1b28a76aeba74744148b15099254d918671Owen Lin        IntentFilter intentFilter = new IntentFilter();
278666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
279666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
280666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
281666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
282666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
283666ea1b28a76aeba74744148b15099254d918671Owen Lin        intentFilter.addDataScheme("file");
284666ea1b28a76aeba74744148b15099254d918671Owen Lin
285666ea1b28a76aeba74744148b15099254d918671Owen Lin        registerReceiver(mReceiver, intentFilter);
286666ea1b28a76aeba74744148b15099254d918671Owen Lin
287666ea1b28a76aeba74744148b15099254d918671Owen Lin        getContentResolver().registerContentObserver(
288666ea1b28a76aeba74744148b15099254d918671Owen Lin                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
289666ea1b28a76aeba74744148b15099254d918671Owen Lin                true, mDbObserver);
290666ea1b28a76aeba74744148b15099254d918671Owen Lin
291666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Assume the storage is mounted and not scanning.
292666ea1b28a76aeba74744148b15099254d918671Owen Lin        mUnmounted = false;
293666ea1b28a76aeba74744148b15099254d918671Owen Lin        mScanning = false;
294666ea1b28a76aeba74744148b15099254d918671Owen Lin        startWorker();
295666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
296666ea1b28a76aeba74744148b15099254d918671Owen Lin
297666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is used to stop the worker thread.
298666ea1b28a76aeba74744148b15099254d918671Owen Lin    volatile boolean mAbort = false;
299666ea1b28a76aeba74744148b15099254d918671Owen Lin
300666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Create the worker thread.
301666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void startWorker() {
302666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAbort = false;
303666ea1b28a76aeba74744148b15099254d918671Owen Lin        mWorkerThread = new Thread("GalleryPicker Worker") {
304666ea1b28a76aeba74744148b15099254d918671Owen Lin            @Override
305666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void run() {
306666ea1b28a76aeba74744148b15099254d918671Owen Lin                workerRun();
307666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
308666ea1b28a76aeba74744148b15099254d918671Owen Lin        };
309666ea1b28a76aeba74744148b15099254d918671Owen Lin        BitmapManager.instance().allowThreadDecoding(mWorkerThread);
310666ea1b28a76aeba74744148b15099254d918671Owen Lin        mWorkerThread.start();
311666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
312666ea1b28a76aeba74744148b15099254d918671Owen Lin
313666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void abortWorker() {
314666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mWorkerThread != null) {
3158aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin            BitmapManager.instance().cancelThreadDecoding(mWorkerThread, getContentResolver());
316666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAbort = true;
317666ea1b28a76aeba74744148b15099254d918671Owen Lin            try {
318666ea1b28a76aeba74744148b15099254d918671Owen Lin                mWorkerThread.join();
319666ea1b28a76aeba74744148b15099254d918671Owen Lin            } catch (InterruptedException ex) {
320666ea1b28a76aeba74744148b15099254d918671Owen Lin                Log.e(TAG, "join interrupted");
321666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
322666ea1b28a76aeba74744148b15099254d918671Owen Lin            mWorkerThread = null;
323666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Remove all runnables in mHandler.
324666ea1b28a76aeba74744148b15099254d918671Owen Lin            // (We assume that the "what" field in the messages are 0
325666ea1b28a76aeba74744148b15099254d918671Owen Lin            // for runnables).
326666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHandler.removeMessages(0);
327666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAdapter.clear();
328666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAdapter.updateDisplay();
329666ea1b28a76aeba74744148b15099254d918671Owen Lin            clearImageLists();
330666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
331666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
332666ea1b28a76aeba74744148b15099254d918671Owen Lin
333666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
334666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void workerRun() {
335666ea1b28a76aeba74744148b15099254d918671Owen Lin        // We collect items from checkImageList() and checkBucketIds() and
336666ea1b28a76aeba74744148b15099254d918671Owen Lin        // put them in allItems. Later we give allItems to checkThumbBitmap()
337666ea1b28a76aeba74744148b15099254d918671Owen Lin        // and generated thumbnail bitmaps for each item. We do this instead of
338666ea1b28a76aeba74744148b15099254d918671Owen Lin        // generating thumbnail bitmaps in checkImageList() and checkBucketIds()
339666ea1b28a76aeba74744148b15099254d918671Owen Lin        // because we want to show all the folders first, then update them with
340666ea1b28a76aeba74744148b15099254d918671Owen Lin        // the thumb bitmaps. (Generating thumbnail bitmaps takes some time.)
341666ea1b28a76aeba74744148b15099254d918671Owen Lin        ArrayList<Item> allItems = new ArrayList<Item>();
342666ea1b28a76aeba74744148b15099254d918671Owen Lin
343666ea1b28a76aeba74744148b15099254d918671Owen Lin        checkScanning();
344666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) return;
345666ea1b28a76aeba74744148b15099254d918671Owen Lin
346666ea1b28a76aeba74744148b15099254d918671Owen Lin        checkImageList(allItems);
347666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) return;
348666ea1b28a76aeba74744148b15099254d918671Owen Lin
349666ea1b28a76aeba74744148b15099254d918671Owen Lin        checkBucketIds(allItems);
350666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) return;
351666ea1b28a76aeba74744148b15099254d918671Owen Lin
352666ea1b28a76aeba74744148b15099254d918671Owen Lin        checkThumbBitmap(allItems);
353666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) return;
354666ea1b28a76aeba74744148b15099254d918671Owen Lin
355666ea1b28a76aeba74744148b15099254d918671Owen Lin        checkLowStorage();
356666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
357666ea1b28a76aeba74744148b15099254d918671Owen Lin
358666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
359666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkScanning() {
360666ea1b28a76aeba74744148b15099254d918671Owen Lin        ContentResolver cr = getContentResolver();
361666ea1b28a76aeba74744148b15099254d918671Owen Lin        final boolean scanning =
362666ea1b28a76aeba74744148b15099254d918671Owen Lin                ImageManager.isMediaScannerScanning(cr);
363666ea1b28a76aeba74744148b15099254d918671Owen Lin        mHandler.post(new Runnable() {
364666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void run() {
365666ea1b28a76aeba74744148b15099254d918671Owen Lin                        checkScanningFinished(scanning);
366666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
367666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
368666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
369666ea1b28a76aeba74744148b15099254d918671Owen Lin
370666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the main thread.
371666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkScanningFinished(boolean scanning) {
372666ea1b28a76aeba74744148b15099254d918671Owen Lin        updateScanningDialog(scanning);
373666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
374666ea1b28a76aeba74744148b15099254d918671Owen Lin
375666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
376666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkImageList(ArrayList<Item> allItems) {
377666ea1b28a76aeba74744148b15099254d918671Owen Lin        int length = IMAGE_LIST_DATA.length;
378666ea1b28a76aeba74744148b15099254d918671Owen Lin        IImageList[] lists = new IImageList[length];
379666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < length; i++) {
380666ea1b28a76aeba74744148b15099254d918671Owen Lin            ImageListData data = IMAGE_LIST_DATA[i];
381666ea1b28a76aeba74744148b15099254d918671Owen Lin            lists[i] = createImageList(data.mInclude, data.mBucketId,
382666ea1b28a76aeba74744148b15099254d918671Owen Lin                    getContentResolver());
383666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mAbort) return;
384666ea1b28a76aeba74744148b15099254d918671Owen Lin            Item item = null;
385666ea1b28a76aeba74744148b15099254d918671Owen Lin
386666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (lists[i].isEmpty()) continue;
387666ea1b28a76aeba74744148b15099254d918671Owen Lin
388666ea1b28a76aeba74744148b15099254d918671Owen Lin            // i >= 3 means we are looking at All Images/All Videos.
389666ea1b28a76aeba74744148b15099254d918671Owen Lin            // lists[i-3] is the corresponding Camera Images/Camera Videos.
390666ea1b28a76aeba74744148b15099254d918671Owen Lin            // We want to add the "All" list only if it's different from
391666ea1b28a76aeba74744148b15099254d918671Owen Lin            // the "Camera" list.
392666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (i >= 3 && lists[i].getCount() == lists[i - 3].getCount()) {
393666ea1b28a76aeba74744148b15099254d918671Owen Lin                continue;
394666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
395666ea1b28a76aeba74744148b15099254d918671Owen Lin
396666ea1b28a76aeba74744148b15099254d918671Owen Lin            item = new Item(data.mType,
397666ea1b28a76aeba74744148b15099254d918671Owen Lin                            data.mBucketId,
398666ea1b28a76aeba74744148b15099254d918671Owen Lin                            getResources().getString(data.mStringId),
399666ea1b28a76aeba74744148b15099254d918671Owen Lin                            lists[i]);
400666ea1b28a76aeba74744148b15099254d918671Owen Lin
401666ea1b28a76aeba74744148b15099254d918671Owen Lin            allItems.add(item);
402666ea1b28a76aeba74744148b15099254d918671Owen Lin
403666ea1b28a76aeba74744148b15099254d918671Owen Lin            final Item finalItem = item;
404666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHandler.post(new Runnable() {
405666ea1b28a76aeba74744148b15099254d918671Owen Lin                        public void run() {
406666ea1b28a76aeba74744148b15099254d918671Owen Lin                            updateItem(finalItem);
407666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
408666ea1b28a76aeba74744148b15099254d918671Owen Lin                    });
409666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
410666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
411666ea1b28a76aeba74744148b15099254d918671Owen Lin
412666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the main thread.
413666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void updateItem(Item item) {
414666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Hide NoImageView if we are going to add the first item
415666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAdapter.getCount() == 0) {
416666ea1b28a76aeba74744148b15099254d918671Owen Lin            hideNoImagesView();
417666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
418666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter.addItem(item);
419666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter.updateDisplay();
420666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
421666ea1b28a76aeba74744148b15099254d918671Owen Lin
422666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String CAMERA_BUCKET =
423666ea1b28a76aeba74744148b15099254d918671Owen Lin            ImageManager.CAMERA_IMAGE_BUCKET_ID;
424666ea1b28a76aeba74744148b15099254d918671Owen Lin
425666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
426666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkBucketIds(ArrayList<Item> allItems) {
427666ea1b28a76aeba74744148b15099254d918671Owen Lin        final IImageList allImages;
428666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (!mScanning && !mUnmounted) {
429666ea1b28a76aeba74744148b15099254d918671Owen Lin            allImages = ImageManager.makeImageList(
430666ea1b28a76aeba74744148b15099254d918671Owen Lin                    getContentResolver(),
431666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ImageManager.DataLocation.ALL,
432666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS,
433666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ImageManager.SORT_DESCENDING,
434666ea1b28a76aeba74744148b15099254d918671Owen Lin                    null);
435666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
436666ea1b28a76aeba74744148b15099254d918671Owen Lin            allImages = ImageManager.makeEmptyImageList();
437666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
438666ea1b28a76aeba74744148b15099254d918671Owen Lin
439666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) {
440666ea1b28a76aeba74744148b15099254d918671Owen Lin            allImages.close();
441666ea1b28a76aeba74744148b15099254d918671Owen Lin            return;
442666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
443666ea1b28a76aeba74744148b15099254d918671Owen Lin
444666ea1b28a76aeba74744148b15099254d918671Owen Lin        HashMap<String, String> hashMap = allImages.getBucketIds();
445666ea1b28a76aeba74744148b15099254d918671Owen Lin        allImages.close();
446666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAbort) return;
447666ea1b28a76aeba74744148b15099254d918671Owen Lin
448666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (Map.Entry<String, String> entry : hashMap.entrySet()) {
449666ea1b28a76aeba74744148b15099254d918671Owen Lin            String key = entry.getKey();
450666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (key == null) {
451666ea1b28a76aeba74744148b15099254d918671Owen Lin                continue;
452666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
453666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (!key.equals(CAMERA_BUCKET)) {
454666ea1b28a76aeba74744148b15099254d918671Owen Lin                IImageList list = createImageList(
455666ea1b28a76aeba74744148b15099254d918671Owen Lin                        ImageManager.INCLUDE_IMAGES
456666ea1b28a76aeba74744148b15099254d918671Owen Lin                        | ImageManager.INCLUDE_VIDEOS, key,
457666ea1b28a76aeba74744148b15099254d918671Owen Lin                        getContentResolver());
458666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (mAbort) return;
459666ea1b28a76aeba74744148b15099254d918671Owen Lin
460666ea1b28a76aeba74744148b15099254d918671Owen Lin                Item item = new Item(Item.TYPE_NORMAL_FOLDERS, key,
461666ea1b28a76aeba74744148b15099254d918671Owen Lin                        entry.getValue(), list);
462666ea1b28a76aeba74744148b15099254d918671Owen Lin
463666ea1b28a76aeba74744148b15099254d918671Owen Lin                allItems.add(item);
464666ea1b28a76aeba74744148b15099254d918671Owen Lin
465666ea1b28a76aeba74744148b15099254d918671Owen Lin                final Item finalItem = item;
466666ea1b28a76aeba74744148b15099254d918671Owen Lin                mHandler.post(new Runnable() {
467666ea1b28a76aeba74744148b15099254d918671Owen Lin                            public void run() {
468666ea1b28a76aeba74744148b15099254d918671Owen Lin                                updateItem(finalItem);
469666ea1b28a76aeba74744148b15099254d918671Owen Lin                            }
470666ea1b28a76aeba74744148b15099254d918671Owen Lin                        });
471666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
472666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
473666ea1b28a76aeba74744148b15099254d918671Owen Lin
474666ea1b28a76aeba74744148b15099254d918671Owen Lin        mHandler.post(new Runnable() {
475666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void run() {
476666ea1b28a76aeba74744148b15099254d918671Owen Lin                        checkBucketIdsFinished();
477666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
478666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
479666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
480666ea1b28a76aeba74744148b15099254d918671Owen Lin
481666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the main thread.
482666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkBucketIdsFinished() {
483666ea1b28a76aeba74744148b15099254d918671Owen Lin
484666ea1b28a76aeba74744148b15099254d918671Owen Lin        // If we just have one folder, open it.
485666ea1b28a76aeba74744148b15099254d918671Owen Lin        // If we have zero folder, show the "no images" icon.
486666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (!mScanning) {
487666ea1b28a76aeba74744148b15099254d918671Owen Lin            int numItems = mAdapter.mItems.size();
488666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (numItems == 0) {
489666ea1b28a76aeba74744148b15099254d918671Owen Lin                showNoImagesView();
490666ea1b28a76aeba74744148b15099254d918671Owen Lin            } else if (numItems == 1) {
491666ea1b28a76aeba74744148b15099254d918671Owen Lin                mAdapter.mItems.get(0).launch(this);
492666ea1b28a76aeba74744148b15099254d918671Owen Lin                finish();
493666ea1b28a76aeba74744148b15099254d918671Owen Lin                return;
494666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
495666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
496666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
497666ea1b28a76aeba74744148b15099254d918671Owen Lin
498666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final int THUMB_SIZE = 142;
499666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
500666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkThumbBitmap(ArrayList<Item> allItems) {
501666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (Item item : allItems) {
502666ea1b28a76aeba74744148b15099254d918671Owen Lin            final Bitmap b = makeMiniThumbBitmap(THUMB_SIZE, THUMB_SIZE,
503666ea1b28a76aeba74744148b15099254d918671Owen Lin                    item.mImageList);
504666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mAbort) {
505666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (b != null) b.recycle();
506666ea1b28a76aeba74744148b15099254d918671Owen Lin                return;
507666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
508666ea1b28a76aeba74744148b15099254d918671Owen Lin
509666ea1b28a76aeba74744148b15099254d918671Owen Lin            final Item finalItem = item;
510666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHandler.post(new Runnable() {
511666ea1b28a76aeba74744148b15099254d918671Owen Lin                        public void run() {
512666ea1b28a76aeba74744148b15099254d918671Owen Lin                            updateThumbBitmap(finalItem, b);
513666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
514666ea1b28a76aeba74744148b15099254d918671Owen Lin                    });
515666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
516666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
517666ea1b28a76aeba74744148b15099254d918671Owen Lin
518666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the main thread.
519666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void updateThumbBitmap(Item item, Bitmap b) {
520666ea1b28a76aeba74744148b15099254d918671Owen Lin        item.setThumbBitmap(b);
521666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAdapter.updateDisplay();
522666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
523666ea1b28a76aeba74744148b15099254d918671Owen Lin
524666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final long LOW_STORAGE_THRESHOLD = 1024 * 1024 * 2;
525666ea1b28a76aeba74744148b15099254d918671Owen Lin
526666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the worker thread.
527666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkLowStorage() {
528666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Check available space only if we are writable
529666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (ImageManager.hasStorage()) {
530666ea1b28a76aeba74744148b15099254d918671Owen Lin            String storageDirectory = Environment
531666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .getExternalStorageDirectory().toString();
532666ea1b28a76aeba74744148b15099254d918671Owen Lin            StatFs stat = new StatFs(storageDirectory);
533666ea1b28a76aeba74744148b15099254d918671Owen Lin            long remaining = (long) stat.getAvailableBlocks()
534666ea1b28a76aeba74744148b15099254d918671Owen Lin                    * (long) stat.getBlockSize();
535666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (remaining < LOW_STORAGE_THRESHOLD) {
536666ea1b28a76aeba74744148b15099254d918671Owen Lin                mHandler.post(new Runnable() {
537666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void run() {
538666ea1b28a76aeba74744148b15099254d918671Owen Lin                        checkLowStorageFinished();
539666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
540666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
541666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
542666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
543666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
544666ea1b28a76aeba74744148b15099254d918671Owen Lin
545666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in the main thread.
546666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is called only if the storage is low.
547666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void checkLowStorageFinished() {
548666ea1b28a76aeba74744148b15099254d918671Owen Lin        Toast.makeText(GalleryPicker.this, R.string.not_enough_space, 5000)
549666ea1b28a76aeba74744148b15099254d918671Owen Lin                .show();
550666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
551666ea1b28a76aeba74744148b15099254d918671Owen Lin
552666ea1b28a76aeba74744148b15099254d918671Owen Lin    // IMAGE_LIST_DATA stores the parameters for the four image lists
553666ea1b28a76aeba74744148b15099254d918671Owen Lin    // we are interested in. The order of the IMAGE_LIST_DATA array is
554666ea1b28a76aeba74744148b15099254d918671Owen Lin    // significant (See the implementation of GalleryPickerAdapter.init).
555666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final class ImageListData {
556666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageListData(int type, int include, String bucketId, int stringId) {
557666ea1b28a76aeba74744148b15099254d918671Owen Lin            mType = type;
558666ea1b28a76aeba74744148b15099254d918671Owen Lin            mInclude = include;
559666ea1b28a76aeba74744148b15099254d918671Owen Lin            mBucketId = bucketId;
560666ea1b28a76aeba74744148b15099254d918671Owen Lin            mStringId = stringId;
561666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
562666ea1b28a76aeba74744148b15099254d918671Owen Lin        int mType;
563666ea1b28a76aeba74744148b15099254d918671Owen Lin        int mInclude;
564666ea1b28a76aeba74744148b15099254d918671Owen Lin        String mBucketId;
565666ea1b28a76aeba74744148b15099254d918671Owen Lin        int mStringId;
566666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
567666ea1b28a76aeba74744148b15099254d918671Owen Lin
568666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final ImageListData[] IMAGE_LIST_DATA = {
569666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Camera Images
570666ea1b28a76aeba74744148b15099254d918671Owen Lin        new ImageListData(Item.TYPE_CAMERA_IMAGES,
571666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.INCLUDE_IMAGES,
572666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.CAMERA_IMAGE_BUCKET_ID,
573666ea1b28a76aeba74744148b15099254d918671Owen Lin                          R.string.gallery_camera_bucket_name),
574666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Camera Videos
575666ea1b28a76aeba74744148b15099254d918671Owen Lin        new ImageListData(Item.TYPE_CAMERA_VIDEOS,
576666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.INCLUDE_VIDEOS,
577666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.CAMERA_IMAGE_BUCKET_ID,
578666ea1b28a76aeba74744148b15099254d918671Owen Lin                          R.string.gallery_camera_videos_bucket_name),
579666ea1b28a76aeba74744148b15099254d918671Owen Lin
580666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Camera Medias
581666ea1b28a76aeba74744148b15099254d918671Owen Lin        new ImageListData(Item.TYPE_CAMERA_MEDIAS,
582666ea1b28a76aeba74744148b15099254d918671Owen Lin                ImageManager.INCLUDE_VIDEOS | ImageManager.INCLUDE_IMAGES,
583666ea1b28a76aeba74744148b15099254d918671Owen Lin                ImageManager.CAMERA_IMAGE_BUCKET_ID,
584666ea1b28a76aeba74744148b15099254d918671Owen Lin                R.string.gallery_camera_media_bucket_name),
585666ea1b28a76aeba74744148b15099254d918671Owen Lin
586666ea1b28a76aeba74744148b15099254d918671Owen Lin        // All Images
587666ea1b28a76aeba74744148b15099254d918671Owen Lin        new ImageListData(Item.TYPE_ALL_IMAGES,
588666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.INCLUDE_IMAGES,
589666ea1b28a76aeba74744148b15099254d918671Owen Lin                          null,
590666ea1b28a76aeba74744148b15099254d918671Owen Lin                          R.string.all_images),
591666ea1b28a76aeba74744148b15099254d918671Owen Lin
592666ea1b28a76aeba74744148b15099254d918671Owen Lin        // All Videos
593666ea1b28a76aeba74744148b15099254d918671Owen Lin        new ImageListData(Item.TYPE_ALL_VIDEOS,
594666ea1b28a76aeba74744148b15099254d918671Owen Lin                          ImageManager.INCLUDE_VIDEOS,
595666ea1b28a76aeba74744148b15099254d918671Owen Lin                          null,
596666ea1b28a76aeba74744148b15099254d918671Owen Lin                          R.string.all_videos),
597666ea1b28a76aeba74744148b15099254d918671Owen Lin    };
598666ea1b28a76aeba74744148b15099254d918671Owen Lin
599666ea1b28a76aeba74744148b15099254d918671Owen Lin
600666ea1b28a76aeba74744148b15099254d918671Owen Lin    // These drawables are loaded on-demand.
601666ea1b28a76aeba74744148b15099254d918671Owen Lin    Drawable mFrameGalleryMask;
602666ea1b28a76aeba74744148b15099254d918671Owen Lin    Drawable mCellOutline;
603666ea1b28a76aeba74744148b15099254d918671Owen Lin    Drawable mVideoOverlay;
604666ea1b28a76aeba74744148b15099254d918671Owen Lin
605666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void loadDrawableIfNeeded() {
606666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mFrameGalleryMask != null) return;  // already loaded
607666ea1b28a76aeba74744148b15099254d918671Owen Lin        Resources r = getResources();
608666ea1b28a76aeba74744148b15099254d918671Owen Lin        mFrameGalleryMask = r.getDrawable(
609666ea1b28a76aeba74744148b15099254d918671Owen Lin                R.drawable.frame_gallery_preview_album_mask);
610666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCellOutline = r.getDrawable(android.R.drawable.gallery_thumb);
611666ea1b28a76aeba74744148b15099254d918671Owen Lin        mVideoOverlay = r.getDrawable(R.drawable.ic_gallery_video_overlay);
612666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
613666ea1b28a76aeba74744148b15099254d918671Owen Lin
614666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void unloadDrawable() {
615666ea1b28a76aeba74744148b15099254d918671Owen Lin        mFrameGalleryMask = null;
616666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCellOutline = null;
617666ea1b28a76aeba74744148b15099254d918671Owen Lin        mVideoOverlay = null;
618666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
619666ea1b28a76aeba74744148b15099254d918671Owen Lin
620666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static void placeImage(Bitmap image, Canvas c, Paint paint,
621666ea1b28a76aeba74744148b15099254d918671Owen Lin            int imageWidth, int widthPadding, int imageHeight,
622666ea1b28a76aeba74744148b15099254d918671Owen Lin            int heightPadding, int offsetX, int offsetY,
623666ea1b28a76aeba74744148b15099254d918671Owen Lin            int pos) {
624666ea1b28a76aeba74744148b15099254d918671Owen Lin        int row = pos / 2;
625666ea1b28a76aeba74744148b15099254d918671Owen Lin        int col = pos - (row * 2);
626666ea1b28a76aeba74744148b15099254d918671Owen Lin
627666ea1b28a76aeba74744148b15099254d918671Owen Lin        int xPos = (col * (imageWidth + widthPadding)) - offsetX;
628666ea1b28a76aeba74744148b15099254d918671Owen Lin        int yPos = (row * (imageHeight + heightPadding)) - offsetY;
629666ea1b28a76aeba74744148b15099254d918671Owen Lin
630666ea1b28a76aeba74744148b15099254d918671Owen Lin        c.drawBitmap(image, xPos, yPos, paint);
631666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
632666ea1b28a76aeba74744148b15099254d918671Owen Lin
633666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is run in worker thread.
634666ea1b28a76aeba74744148b15099254d918671Owen Lin    private Bitmap makeMiniThumbBitmap(int width, int height,
635666ea1b28a76aeba74744148b15099254d918671Owen Lin            IImageList images) {
636666ea1b28a76aeba74744148b15099254d918671Owen Lin        int count = images.getCount();
637666ea1b28a76aeba74744148b15099254d918671Owen Lin        // We draw three different version of the folder image depending on the
638666ea1b28a76aeba74744148b15099254d918671Owen Lin        // number of images in the folder.
639666ea1b28a76aeba74744148b15099254d918671Owen Lin        //    For a single image, that image draws over the whole folder.
640666ea1b28a76aeba74744148b15099254d918671Owen Lin        //    For two or three images, we draw the two most recent photos.
641666ea1b28a76aeba74744148b15099254d918671Owen Lin        //    For four or more images, we draw four photos.
642666ea1b28a76aeba74744148b15099254d918671Owen Lin        final int padding = 4;
643666ea1b28a76aeba74744148b15099254d918671Owen Lin        int imageWidth = width;
644666ea1b28a76aeba74744148b15099254d918671Owen Lin        int imageHeight = height;
645666ea1b28a76aeba74744148b15099254d918671Owen Lin        int offsetWidth = 0;
646666ea1b28a76aeba74744148b15099254d918671Owen Lin        int offsetHeight = 0;
647666ea1b28a76aeba74744148b15099254d918671Owen Lin
648666ea1b28a76aeba74744148b15099254d918671Owen Lin        imageWidth = (imageWidth - padding) / 2;  // 2 here because we show two
649666ea1b28a76aeba74744148b15099254d918671Owen Lin                                                  // images
650666ea1b28a76aeba74744148b15099254d918671Owen Lin        imageHeight = (imageHeight - padding) / 2;  // per row and column
651666ea1b28a76aeba74744148b15099254d918671Owen Lin
652666ea1b28a76aeba74744148b15099254d918671Owen Lin        final Paint p = new Paint();
653666ea1b28a76aeba74744148b15099254d918671Owen Lin        final Bitmap b = Bitmap.createBitmap(width, height,
654666ea1b28a76aeba74744148b15099254d918671Owen Lin                Bitmap.Config.ARGB_8888);
655666ea1b28a76aeba74744148b15099254d918671Owen Lin        final Canvas c = new Canvas(b);
656666ea1b28a76aeba74744148b15099254d918671Owen Lin        final Matrix m = new Matrix();
657666ea1b28a76aeba74744148b15099254d918671Owen Lin
658666ea1b28a76aeba74744148b15099254d918671Owen Lin        // draw the whole canvas as transparent
659666ea1b28a76aeba74744148b15099254d918671Owen Lin        p.setColor(0x00000000);
660666ea1b28a76aeba74744148b15099254d918671Owen Lin        c.drawPaint(p);
661666ea1b28a76aeba74744148b15099254d918671Owen Lin
662666ea1b28a76aeba74744148b15099254d918671Owen Lin        // load the drawables
663666ea1b28a76aeba74744148b15099254d918671Owen Lin        loadDrawableIfNeeded();
664666ea1b28a76aeba74744148b15099254d918671Owen Lin
665666ea1b28a76aeba74744148b15099254d918671Owen Lin        // draw the mask normally
666666ea1b28a76aeba74744148b15099254d918671Owen Lin        p.setColor(0xFFFFFFFF);
667666ea1b28a76aeba74744148b15099254d918671Owen Lin        mFrameGalleryMask.setBounds(0, 0, width, height);
668666ea1b28a76aeba74744148b15099254d918671Owen Lin        mFrameGalleryMask.draw(c);
669666ea1b28a76aeba74744148b15099254d918671Owen Lin
670666ea1b28a76aeba74744148b15099254d918671Owen Lin        Paint pdpaint = new Paint();
671666ea1b28a76aeba74744148b15099254d918671Owen Lin        pdpaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
672666ea1b28a76aeba74744148b15099254d918671Owen Lin
673666ea1b28a76aeba74744148b15099254d918671Owen Lin        pdpaint.setStyle(Paint.Style.FILL);
674666ea1b28a76aeba74744148b15099254d918671Owen Lin        c.drawRect(0, 0, width, height, pdpaint);
675666ea1b28a76aeba74744148b15099254d918671Owen Lin
676666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < 4; i++) {
677666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mAbort) {
678666ea1b28a76aeba74744148b15099254d918671Owen Lin                return null;
679666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
680666ea1b28a76aeba74744148b15099254d918671Owen Lin
681666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap temp = null;
682666ea1b28a76aeba74744148b15099254d918671Owen Lin            IImage image = i < count ? images.getImageAt(i) : null;
683666ea1b28a76aeba74744148b15099254d918671Owen Lin
684666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (image != null) {
685666ea1b28a76aeba74744148b15099254d918671Owen Lin                temp = image.miniThumbBitmap();
686666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
687666ea1b28a76aeba74744148b15099254d918671Owen Lin
688666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (temp != null) {
689666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (ImageManager.isVideo(image)) {
690666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Bitmap newMap = temp.copy(temp.getConfig(), true);
691666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Canvas overlayCanvas = new Canvas(newMap);
692666ea1b28a76aeba74744148b15099254d918671Owen Lin                    int overlayWidth = mVideoOverlay.getIntrinsicWidth();
693666ea1b28a76aeba74744148b15099254d918671Owen Lin                    int overlayHeight = mVideoOverlay.getIntrinsicHeight();
694666ea1b28a76aeba74744148b15099254d918671Owen Lin                    int left = (newMap.getWidth() - overlayWidth) / 2;
695666ea1b28a76aeba74744148b15099254d918671Owen Lin                    int top = (newMap.getHeight() - overlayHeight) / 2;
696666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Rect newBounds = new Rect(left, top, left + overlayWidth,
697666ea1b28a76aeba74744148b15099254d918671Owen Lin                            top + overlayHeight);
698666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mVideoOverlay.setBounds(newBounds);
699666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mVideoOverlay.draw(overlayCanvas);
700666ea1b28a76aeba74744148b15099254d918671Owen Lin                    temp.recycle();
701666ea1b28a76aeba74744148b15099254d918671Owen Lin                    temp = newMap;
702666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
703666ea1b28a76aeba74744148b15099254d918671Owen Lin
704666ea1b28a76aeba74744148b15099254d918671Owen Lin                temp = Util.transform(m, temp, imageWidth,
705666ea1b28a76aeba74744148b15099254d918671Owen Lin                        imageHeight, true, Util.RECYCLE_INPUT);
706666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
707666ea1b28a76aeba74744148b15099254d918671Owen Lin
708666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap thumb = Bitmap.createBitmap(imageWidth, imageHeight,
709666ea1b28a76aeba74744148b15099254d918671Owen Lin                                               Bitmap.Config.ARGB_8888);
710666ea1b28a76aeba74744148b15099254d918671Owen Lin            Canvas tempCanvas = new Canvas(thumb);
711666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (temp != null) {
712666ea1b28a76aeba74744148b15099254d918671Owen Lin                tempCanvas.drawBitmap(temp, new Matrix(), new Paint());
713666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
714666ea1b28a76aeba74744148b15099254d918671Owen Lin            mCellOutline.setBounds(0, 0, imageWidth, imageHeight);
715666ea1b28a76aeba74744148b15099254d918671Owen Lin            mCellOutline.draw(tempCanvas);
716666ea1b28a76aeba74744148b15099254d918671Owen Lin
717666ea1b28a76aeba74744148b15099254d918671Owen Lin            placeImage(thumb, c, pdpaint, imageWidth, padding, imageHeight,
718666ea1b28a76aeba74744148b15099254d918671Owen Lin                       padding, offsetWidth, offsetHeight, i);
719666ea1b28a76aeba74744148b15099254d918671Owen Lin
720666ea1b28a76aeba74744148b15099254d918671Owen Lin            thumb.recycle();
721666ea1b28a76aeba74744148b15099254d918671Owen Lin
722666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (temp != null) {
723666ea1b28a76aeba74744148b15099254d918671Owen Lin                temp.recycle();
724666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
725666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
726666ea1b28a76aeba74744148b15099254d918671Owen Lin
727666ea1b28a76aeba74744148b15099254d918671Owen Lin        return b;
728666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
729666ea1b28a76aeba74744148b15099254d918671Owen Lin
730666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
731666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean onCreateOptionsMenu(Menu menu) {
732666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onCreateOptionsMenu(menu);
733666ea1b28a76aeba74744148b15099254d918671Owen Lin
734666ea1b28a76aeba74744148b15099254d918671Owen Lin        MenuHelper.addCaptureMenuItems(menu, this);
735666ea1b28a76aeba74744148b15099254d918671Owen Lin
736666ea1b28a76aeba74744148b15099254d918671Owen Lin        menu.add(Menu.NONE, Menu.NONE, MenuHelper.POSITION_GALLERY_SETTING,
737666ea1b28a76aeba74744148b15099254d918671Owen Lin                R.string.camerasettings)
738666ea1b28a76aeba74744148b15099254d918671Owen Lin                .setOnMenuItemClickListener(new OnMenuItemClickListener() {
739666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public boolean onMenuItemClick(MenuItem item) {
740666ea1b28a76aeba74744148b15099254d918671Owen Lin                        Intent preferences = new Intent();
741666ea1b28a76aeba74744148b15099254d918671Owen Lin                        preferences.setClass(GalleryPicker.this,
742666ea1b28a76aeba74744148b15099254d918671Owen Lin                                             GallerySettings.class);
743666ea1b28a76aeba74744148b15099254d918671Owen Lin                        startActivity(preferences);
744666ea1b28a76aeba74744148b15099254d918671Owen Lin                        return true;
745666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
746666ea1b28a76aeba74744148b15099254d918671Owen Lin                })
747666ea1b28a76aeba74744148b15099254d918671Owen Lin                .setAlphabeticShortcut('p')
748666ea1b28a76aeba74744148b15099254d918671Owen Lin                .setIcon(android.R.drawable.ic_menu_preferences);
749666ea1b28a76aeba74744148b15099254d918671Owen Lin
750666ea1b28a76aeba74744148b15099254d918671Owen Lin        return true;
751666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
752666ea1b28a76aeba74744148b15099254d918671Owen Lin
753666ea1b28a76aeba74744148b15099254d918671Owen Lin    // image lists created by createImageList() are collected in mAllLists.
754666ea1b28a76aeba74744148b15099254d918671Owen Lin    // They will be closed in clearImageList, so they don't hold open files
755666ea1b28a76aeba74744148b15099254d918671Owen Lin    // on SD card. We will be killed if we don't close files when the SD card
756666ea1b28a76aeba74744148b15099254d918671Owen Lin    // is unmounted.
757666ea1b28a76aeba74744148b15099254d918671Owen Lin    ArrayList<IImageList> mAllLists = new ArrayList<IImageList>();
758666ea1b28a76aeba74744148b15099254d918671Owen Lin
759666ea1b28a76aeba74744148b15099254d918671Owen Lin    private IImageList createImageList(int mediaTypes, String bucketId,
760666ea1b28a76aeba74744148b15099254d918671Owen Lin            ContentResolver cr) {
761666ea1b28a76aeba74744148b15099254d918671Owen Lin        IImageList list = ImageManager.makeImageList(
762666ea1b28a76aeba74744148b15099254d918671Owen Lin                cr,
763666ea1b28a76aeba74744148b15099254d918671Owen Lin                ImageManager.DataLocation.ALL,
764666ea1b28a76aeba74744148b15099254d918671Owen Lin                mediaTypes,
765666ea1b28a76aeba74744148b15099254d918671Owen Lin                ImageManager.SORT_DESCENDING,
766666ea1b28a76aeba74744148b15099254d918671Owen Lin                bucketId);
767666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAllLists.add(list);
768666ea1b28a76aeba74744148b15099254d918671Owen Lin        return list;
769666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
770666ea1b28a76aeba74744148b15099254d918671Owen Lin
771666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void clearImageLists() {
772666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (IImageList list : mAllLists) {
773666ea1b28a76aeba74744148b15099254d918671Owen Lin            list.close();
774666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
775666ea1b28a76aeba74744148b15099254d918671Owen Lin        mAllLists.clear();
776666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
777666ea1b28a76aeba74744148b15099254d918671Owen Lin}
778666ea1b28a76aeba74744148b15099254d918671Owen Lin
779666ea1b28a76aeba74744148b15099254d918671Owen Lin// Item is the underlying data for GalleryPickerAdapter.
780666ea1b28a76aeba74744148b15099254d918671Owen Lin// It is passed from the activity to the adapter.
781666ea1b28a76aeba74744148b15099254d918671Owen Linclass Item {
782666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_NONE = -1;
783666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_ALL_IMAGES = 0;
784666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_ALL_VIDEOS = 1;
785666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_CAMERA_IMAGES = 2;
786666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_CAMERA_VIDEOS = 3;
787666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_CAMERA_MEDIAS = 4;
788666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int TYPE_NORMAL_FOLDERS = 5;
789666ea1b28a76aeba74744148b15099254d918671Owen Lin
790666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final int mType;
791666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final String mBucketId;
792666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final String mName;
793666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final IImageList mImageList;
794666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final int mCount;
795666ea1b28a76aeba74744148b15099254d918671Owen Lin    public final Uri mFirstImageUri;  // could be null if the list is empty
796666ea1b28a76aeba74744148b15099254d918671Owen Lin
797666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The thumbnail bitmap is set by setThumbBitmap() later because we want
798666ea1b28a76aeba74744148b15099254d918671Owen Lin    // to let the user sees the folder icon as soon as possible (and possibly
799666ea1b28a76aeba74744148b15099254d918671Owen Lin    // select them), then present more detailed information when we have it.
800666ea1b28a76aeba74744148b15099254d918671Owen Lin    public Bitmap mThumbBitmap;  // the thumbnail bitmap for the image list
801666ea1b28a76aeba74744148b15099254d918671Owen Lin
802666ea1b28a76aeba74744148b15099254d918671Owen Lin    public Item(int type, String bucketId, String name, IImageList list) {
803666ea1b28a76aeba74744148b15099254d918671Owen Lin        mType = type;
804666ea1b28a76aeba74744148b15099254d918671Owen Lin        mBucketId = bucketId;
805666ea1b28a76aeba74744148b15099254d918671Owen Lin        mName = name;
806666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageList = list;
807666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCount = list.getCount();
808666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mCount > 0) {
809666ea1b28a76aeba74744148b15099254d918671Owen Lin            mFirstImageUri = list.getImageAt(0).fullSizeImageUri();
810666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
811666ea1b28a76aeba74744148b15099254d918671Owen Lin            mFirstImageUri = null;
812666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
813666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
814666ea1b28a76aeba74744148b15099254d918671Owen Lin
815666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void setThumbBitmap(Bitmap thumbBitmap) {
816666ea1b28a76aeba74744148b15099254d918671Owen Lin        mThumbBitmap = thumbBitmap;
817666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
818666ea1b28a76aeba74744148b15099254d918671Owen Lin
819666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean needsBucketId() {
820666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mType >= TYPE_CAMERA_IMAGES;
821666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
822666ea1b28a76aeba74744148b15099254d918671Owen Lin
823666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void launch(Activity activity) {
824666ea1b28a76aeba74744148b15099254d918671Owen Lin        Uri uri = Images.Media.INTERNAL_CONTENT_URI;
825666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (needsBucketId()) {
826666ea1b28a76aeba74744148b15099254d918671Owen Lin            uri = uri.buildUpon()
827666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .appendQueryParameter("bucketId", mBucketId).build();
828666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
829666ea1b28a76aeba74744148b15099254d918671Owen Lin        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
830666ea1b28a76aeba74744148b15099254d918671Owen Lin        intent.putExtra("windowTitle", mName);
831666ea1b28a76aeba74744148b15099254d918671Owen Lin        intent.putExtra("mediaTypes", getIncludeMediaTypes());
832666ea1b28a76aeba74744148b15099254d918671Owen Lin        activity.startActivity(intent);
833666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
834666ea1b28a76aeba74744148b15099254d918671Owen Lin
835666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int getIncludeMediaTypes() {
836666ea1b28a76aeba74744148b15099254d918671Owen Lin        return convertItemTypeToIncludedMediaType(mType);
837666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
838666ea1b28a76aeba74744148b15099254d918671Owen Lin
839666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static int convertItemTypeToIncludedMediaType(int itemType) {
840666ea1b28a76aeba74744148b15099254d918671Owen Lin        switch (itemType) {
841666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_ALL_IMAGES:
842666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_CAMERA_IMAGES:
843666ea1b28a76aeba74744148b15099254d918671Owen Lin            return ImageManager.INCLUDE_IMAGES;
844666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_ALL_VIDEOS:
845666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_CAMERA_VIDEOS:
846666ea1b28a76aeba74744148b15099254d918671Owen Lin            return ImageManager.INCLUDE_VIDEOS;
847666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_NORMAL_FOLDERS:
848666ea1b28a76aeba74744148b15099254d918671Owen Lin        case TYPE_CAMERA_MEDIAS:
849666ea1b28a76aeba74744148b15099254d918671Owen Lin        default:
850666ea1b28a76aeba74744148b15099254d918671Owen Lin            return ImageManager.INCLUDE_IMAGES
851666ea1b28a76aeba74744148b15099254d918671Owen Lin                    | ImageManager.INCLUDE_VIDEOS;
852666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
853666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
854666ea1b28a76aeba74744148b15099254d918671Owen Lin
855666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int getOverlay() {
856666ea1b28a76aeba74744148b15099254d918671Owen Lin        switch (mType) {
857666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_ALL_IMAGES:
858666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_CAMERA_IMAGES:
859666ea1b28a76aeba74744148b15099254d918671Owen Lin                return R.drawable.frame_overlay_gallery_camera;
860666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_ALL_VIDEOS:
861666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_CAMERA_VIDEOS:
862666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_CAMERA_MEDIAS:
863666ea1b28a76aeba74744148b15099254d918671Owen Lin                return R.drawable.frame_overlay_gallery_video;
864666ea1b28a76aeba74744148b15099254d918671Owen Lin            case TYPE_NORMAL_FOLDERS:
865666ea1b28a76aeba74744148b15099254d918671Owen Lin            default:
866666ea1b28a76aeba74744148b15099254d918671Owen Lin                return R.drawable.frame_overlay_gallery_folder;
867666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
868666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
869666ea1b28a76aeba74744148b15099254d918671Owen Lin}
870666ea1b28a76aeba74744148b15099254d918671Owen Lin
871666ea1b28a76aeba74744148b15099254d918671Owen Linclass GalleryPickerAdapter extends BaseAdapter {
872666ea1b28a76aeba74744148b15099254d918671Owen Lin    ArrayList<Item> mItems = new ArrayList<Item>();
873666ea1b28a76aeba74744148b15099254d918671Owen Lin    LayoutInflater mInflater;
874666ea1b28a76aeba74744148b15099254d918671Owen Lin
875666ea1b28a76aeba74744148b15099254d918671Owen Lin    GalleryPickerAdapter(LayoutInflater inflater) {
876666ea1b28a76aeba74744148b15099254d918671Owen Lin        mInflater = inflater;
877666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
878666ea1b28a76aeba74744148b15099254d918671Owen Lin
879666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void addItem(Item item) {
880666ea1b28a76aeba74744148b15099254d918671Owen Lin        mItems.add(item);
881666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
882666ea1b28a76aeba74744148b15099254d918671Owen Lin
883666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void updateDisplay() {
884666ea1b28a76aeba74744148b15099254d918671Owen Lin        notifyDataSetChanged();
885666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
886666ea1b28a76aeba74744148b15099254d918671Owen Lin
887666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void clear() {
888666ea1b28a76aeba74744148b15099254d918671Owen Lin        mItems.clear();
889666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
890666ea1b28a76aeba74744148b15099254d918671Owen Lin
891666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int getCount() {
892666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mItems.size();
893666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
894666ea1b28a76aeba74744148b15099254d918671Owen Lin
895666ea1b28a76aeba74744148b15099254d918671Owen Lin    public Object getItem(int position) {
896666ea1b28a76aeba74744148b15099254d918671Owen Lin        return null;
897666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
898666ea1b28a76aeba74744148b15099254d918671Owen Lin
899666ea1b28a76aeba74744148b15099254d918671Owen Lin    public long getItemId(int position) {
900666ea1b28a76aeba74744148b15099254d918671Owen Lin        return position;
901666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
902666ea1b28a76aeba74744148b15099254d918671Owen Lin
903666ea1b28a76aeba74744148b15099254d918671Owen Lin    public String baseTitleForPosition(int position) {
904666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mItems.get(position).mName;
905666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
906666ea1b28a76aeba74744148b15099254d918671Owen Lin
907666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int getIncludeMediaTypes(int position) {
908666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mItems.get(position).getIncludeMediaTypes();
909666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
910666ea1b28a76aeba74744148b15099254d918671Owen Lin
911666ea1b28a76aeba74744148b15099254d918671Owen Lin    public View getView(final int position, View convertView,
912666ea1b28a76aeba74744148b15099254d918671Owen Lin                        ViewGroup parent) {
913666ea1b28a76aeba74744148b15099254d918671Owen Lin        View v;
914666ea1b28a76aeba74744148b15099254d918671Owen Lin
915666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (convertView == null) {
916666ea1b28a76aeba74744148b15099254d918671Owen Lin            v = mInflater.inflate(R.layout.gallery_picker_item, null);
917666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
918666ea1b28a76aeba74744148b15099254d918671Owen Lin            v = convertView;
919666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
920666ea1b28a76aeba74744148b15099254d918671Owen Lin
921666ea1b28a76aeba74744148b15099254d918671Owen Lin        TextView titleView = (TextView) v.findViewById(R.id.title);
922666ea1b28a76aeba74744148b15099254d918671Owen Lin
923666ea1b28a76aeba74744148b15099254d918671Owen Lin        GalleryPickerItem iv =
924666ea1b28a76aeba74744148b15099254d918671Owen Lin                (GalleryPickerItem) v.findViewById(R.id.thumbnail);
925666ea1b28a76aeba74744148b15099254d918671Owen Lin        Item item = mItems.get(position);
926666ea1b28a76aeba74744148b15099254d918671Owen Lin        iv.setOverlay(item.getOverlay());
927666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (item.mThumbBitmap != null) {
928666ea1b28a76aeba74744148b15099254d918671Owen Lin            iv.setImageBitmap(item.mThumbBitmap);
929666ea1b28a76aeba74744148b15099254d918671Owen Lin            String title = item.mName + " (" + item.mCount + ")";
930666ea1b28a76aeba74744148b15099254d918671Owen Lin            titleView.setText(title);
931666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
932666ea1b28a76aeba74744148b15099254d918671Owen Lin            iv.setImageResource(android.R.color.transparent);
933666ea1b28a76aeba74744148b15099254d918671Owen Lin            titleView.setText(item.mName);
934666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
935666ea1b28a76aeba74744148b15099254d918671Owen Lin
936666ea1b28a76aeba74744148b15099254d918671Owen Lin        // An workaround due to a bug in TextView. If the length of text is
937666ea1b28a76aeba74744148b15099254d918671Owen Lin        // different from the previous in convertView, the layout would be
938666ea1b28a76aeba74744148b15099254d918671Owen Lin        // wrong.
939666ea1b28a76aeba74744148b15099254d918671Owen Lin        titleView.requestLayout();
940666ea1b28a76aeba74744148b15099254d918671Owen Lin
941666ea1b28a76aeba74744148b15099254d918671Owen Lin        return v;
942666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
943666ea1b28a76aeba74744148b15099254d918671Owen Lin}
944