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
19666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.BaseImageList;
20666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.DrmImageList;
21666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage;
22666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImageList;
23666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.ImageList;
24666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.ImageListUber;
25666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.SingleImageList;
26666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.VideoList;
27666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.VideoObject;
28666ea1b28a76aeba74744148b15099254d918671Owen Lin
29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver;
30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentValues;
31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.database.Cursor;
32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap;
33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap.CompressFormat;
34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.location.Location;
35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.media.ExifInterface;
36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri;
37666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Environment;
38666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Parcel;
39666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Parcelable;
40666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.DrmStore;
41666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore;
42666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore.Images;
43666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log;
44666ea1b28a76aeba74744148b15099254d918671Owen Lin
45666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.File;
46666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.FileNotFoundException;
47666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.FileOutputStream;
48666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.IOException;
49666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.OutputStream;
50666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.ArrayList;
51666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.HashMap;
52666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.Iterator;
53666ea1b28a76aeba74744148b15099254d918671Owen Lin
54666ea1b28a76aeba74744148b15099254d918671Owen Lin/**
55666ea1b28a76aeba74744148b15099254d918671Owen Lin * ImageManager is used to retrieve and store images
56666ea1b28a76aeba74744148b15099254d918671Owen Lin * in the media content provider.
57666ea1b28a76aeba74744148b15099254d918671Owen Lin */
58666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class ImageManager {
59666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String TAG = "ImageManager";
60666ea1b28a76aeba74744148b15099254d918671Owen Lin
61666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final Uri STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI;
62666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final Uri THUMB_URI
63666ea1b28a76aeba74744148b15099254d918671Owen Lin            = Images.Thumbnails.EXTERNAL_CONTENT_URI;
64666ea1b28a76aeba74744148b15099254d918671Owen Lin
65666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final Uri VIDEO_STORAGE_URI =
66666ea1b28a76aeba74744148b15099254d918671Owen Lin            Uri.parse("content://media/external/video/media");
67666ea1b28a76aeba74744148b15099254d918671Owen Lin
68666ea1b28a76aeba74744148b15099254d918671Owen Lin    // ImageListParam specifies all the parameters we need to create an image
69666ea1b28a76aeba74744148b15099254d918671Owen Lin    // list (we also need a ContentResolver).
70666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static class ImageListParam implements Parcelable {
71666ea1b28a76aeba74744148b15099254d918671Owen Lin        public DataLocation mLocation;
72666ea1b28a76aeba74744148b15099254d918671Owen Lin        public int mInclusion;
73666ea1b28a76aeba74744148b15099254d918671Owen Lin        public int mSort;
74666ea1b28a76aeba74744148b15099254d918671Owen Lin        public String mBucketId;
75666ea1b28a76aeba74744148b15099254d918671Owen Lin
76666ea1b28a76aeba74744148b15099254d918671Owen Lin        // This is only used if we are creating a single image list.
77666ea1b28a76aeba74744148b15099254d918671Owen Lin        public Uri mSingleImageUri;
78666ea1b28a76aeba74744148b15099254d918671Owen Lin
79666ea1b28a76aeba74744148b15099254d918671Owen Lin        // This is only used if we are creating an empty image list.
80666ea1b28a76aeba74744148b15099254d918671Owen Lin        public boolean mIsEmptyImageList;
81666ea1b28a76aeba74744148b15099254d918671Owen Lin
82666ea1b28a76aeba74744148b15099254d918671Owen Lin        public ImageListParam() {}
83666ea1b28a76aeba74744148b15099254d918671Owen Lin
84666ea1b28a76aeba74744148b15099254d918671Owen Lin        public void writeToParcel(Parcel out, int flags) {
85666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeInt(mLocation.ordinal());
86666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeInt(mInclusion);
87666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeInt(mSort);
88666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeString(mBucketId);
89666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeParcelable(mSingleImageUri, flags);
90666ea1b28a76aeba74744148b15099254d918671Owen Lin            out.writeInt(mIsEmptyImageList ? 1 : 0);
91666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
92666ea1b28a76aeba74744148b15099254d918671Owen Lin
93666ea1b28a76aeba74744148b15099254d918671Owen Lin        private ImageListParam(Parcel in) {
94666ea1b28a76aeba74744148b15099254d918671Owen Lin            mLocation = DataLocation.values()[in.readInt()];
95666ea1b28a76aeba74744148b15099254d918671Owen Lin            mInclusion = in.readInt();
96666ea1b28a76aeba74744148b15099254d918671Owen Lin            mSort = in.readInt();
97666ea1b28a76aeba74744148b15099254d918671Owen Lin            mBucketId = in.readString();
98666ea1b28a76aeba74744148b15099254d918671Owen Lin            mSingleImageUri = in.readParcelable(null);
99666ea1b28a76aeba74744148b15099254d918671Owen Lin            mIsEmptyImageList = (in.readInt() != 0);
100666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
101666ea1b28a76aeba74744148b15099254d918671Owen Lin
102666ea1b28a76aeba74744148b15099254d918671Owen Lin        public String toString() {
103666ea1b28a76aeba74744148b15099254d918671Owen Lin            return String.format("ImageListParam{loc=%s,inc=%d,sort=%d," +
104666ea1b28a76aeba74744148b15099254d918671Owen Lin                "bucket=%s,empty=%b,single=%s}", mLocation, mInclusion,
105666ea1b28a76aeba74744148b15099254d918671Owen Lin                mSort, mBucketId, mIsEmptyImageList, mSingleImageUri);
106666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
107666ea1b28a76aeba74744148b15099254d918671Owen Lin
108666ea1b28a76aeba74744148b15099254d918671Owen Lin        public static final Parcelable.Creator CREATOR
109666ea1b28a76aeba74744148b15099254d918671Owen Lin                = new Parcelable.Creator() {
110666ea1b28a76aeba74744148b15099254d918671Owen Lin            public ImageListParam createFromParcel(Parcel in) {
111666ea1b28a76aeba74744148b15099254d918671Owen Lin                return new ImageListParam(in);
112666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
113666ea1b28a76aeba74744148b15099254d918671Owen Lin
114666ea1b28a76aeba74744148b15099254d918671Owen Lin            public ImageListParam[] newArray(int size) {
115666ea1b28a76aeba74744148b15099254d918671Owen Lin                return new ImageListParam[size];
116666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
117666ea1b28a76aeba74744148b15099254d918671Owen Lin        };
118666ea1b28a76aeba74744148b15099254d918671Owen Lin
119666ea1b28a76aeba74744148b15099254d918671Owen Lin        public int describeContents() {
120666ea1b28a76aeba74744148b15099254d918671Owen Lin            return 0;
121666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
122666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
123666ea1b28a76aeba74744148b15099254d918671Owen Lin
124666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Location
125666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static enum DataLocation { NONE, INTERNAL, EXTERNAL, ALL }
126666ea1b28a76aeba74744148b15099254d918671Owen Lin
127666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Inclusion
128666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int INCLUDE_IMAGES = (1 << 0);
129666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int INCLUDE_DRM_IMAGES = (1 << 1);
130666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int INCLUDE_VIDEOS = (1 << 2);
131666ea1b28a76aeba74744148b15099254d918671Owen Lin
132666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Sort
133666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int SORT_ASCENDING = 1;
134666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final int SORT_DESCENDING = 2;
135666ea1b28a76aeba74744148b15099254d918671Owen Lin
136666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final String CAMERA_IMAGE_BUCKET_NAME =
137666ea1b28a76aeba74744148b15099254d918671Owen Lin            Environment.getExternalStorageDirectory().toString()
138666ea1b28a76aeba74744148b15099254d918671Owen Lin            + "/DCIM/Camera";
139666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static final String CAMERA_IMAGE_BUCKET_ID =
140666ea1b28a76aeba74744148b15099254d918671Owen Lin            getBucketId(CAMERA_IMAGE_BUCKET_NAME);
141666ea1b28a76aeba74744148b15099254d918671Owen Lin
142666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
143666ea1b28a76aeba74744148b15099254d918671Owen Lin     * Matches code in MediaProvider.computeBucketValues. Should be a common
144666ea1b28a76aeba74744148b15099254d918671Owen Lin     * function.
145666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
146666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static String getBucketId(String path) {
147666ea1b28a76aeba74744148b15099254d918671Owen Lin        return String.valueOf(path.toLowerCase().hashCode());
148666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
149666ea1b28a76aeba74744148b15099254d918671Owen Lin
150666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
151666ea1b28a76aeba74744148b15099254d918671Owen Lin     * OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be
152666ea1b28a76aeba74744148b15099254d918671Owen Lin     * imported. This is a temporary fix for bug#1655552.
153666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
154666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static void ensureOSXCompatibleFolder() {
155666ea1b28a76aeba74744148b15099254d918671Owen Lin        File nnnAAAAA = new File(
156666ea1b28a76aeba74744148b15099254d918671Owen Lin            Environment.getExternalStorageDirectory().toString()
157666ea1b28a76aeba74744148b15099254d918671Owen Lin            + "/DCIM/100ANDRO");
158666ea1b28a76aeba74744148b15099254d918671Owen Lin        if ((!nnnAAAAA.exists()) && (!nnnAAAAA.mkdir())) {
159666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.e(TAG, "create NNNAAAAA file: " + nnnAAAAA.getPath()
160666ea1b28a76aeba74744148b15099254d918671Owen Lin                    + " failed");
161666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
162666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
163666ea1b28a76aeba74744148b15099254d918671Owen Lin
164666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
165666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @return true if the mimetype is an image mimetype.
166666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
167666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean isImageMimeType(String mimeType) {
168666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mimeType.startsWith("image/");
169666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
170666ea1b28a76aeba74744148b15099254d918671Owen Lin
171666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
172666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @return true if the mimetype is a video mimetype.
173666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
174666ea1b28a76aeba74744148b15099254d918671Owen Lin    /* This is commented out because isVideo is not calling this now.
175666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean isVideoMimeType(String mimeType) {
176666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mimeType.startsWith("video/");
177666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
178666ea1b28a76aeba74744148b15099254d918671Owen Lin    */
179666ea1b28a76aeba74744148b15099254d918671Owen Lin
180666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
181666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @return true if the image is an image.
182666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
183666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean isImage(IImage image) {
184666ea1b28a76aeba74744148b15099254d918671Owen Lin        return isImageMimeType(image.getMimeType());
185666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
186666ea1b28a76aeba74744148b15099254d918671Owen Lin
187666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
188666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @return true if the image is a video.
189666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
190666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean isVideo(IImage image) {
191666ea1b28a76aeba74744148b15099254d918671Owen Lin        // This is the right implementation, but we use instanceof for speed.
192666ea1b28a76aeba74744148b15099254d918671Owen Lin        //return isVideoMimeType(image.getMimeType());
193666ea1b28a76aeba74744148b15099254d918671Owen Lin        return (image instanceof VideoObject);
194666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
195666ea1b28a76aeba74744148b15099254d918671Owen Lin
196666ea1b28a76aeba74744148b15099254d918671Owen Lin    //
197666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Stores a bitmap or a jpeg byte array to a file (using the specified
198666ea1b28a76aeba74744148b15099254d918671Owen Lin    // directory and filename). Also add an entry to the media store for
199666ea1b28a76aeba74744148b15099254d918671Owen Lin    // this picture. The title, dateTaken, location are attributes for the
200666ea1b28a76aeba74744148b15099254d918671Owen Lin    // picture. The degree is a one element array which returns the orientation
201666ea1b28a76aeba74744148b15099254d918671Owen Lin    // of the picture.
202666ea1b28a76aeba74744148b15099254d918671Owen Lin    //
203666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static Uri addImage(ContentResolver cr, String title, long dateTaken,
204666ea1b28a76aeba74744148b15099254d918671Owen Lin            Location location, String directory, String filename,
205666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap source, byte[] jpegData, int[] degree) {
206666ea1b28a76aeba74744148b15099254d918671Owen Lin        // We should store image data earlier than insert it to ContentProvider, otherwise
207666ea1b28a76aeba74744148b15099254d918671Owen Lin        // we may not be able to generate thumbnail in time.
208666ea1b28a76aeba74744148b15099254d918671Owen Lin        OutputStream outputStream = null;
209666ea1b28a76aeba74744148b15099254d918671Owen Lin        String filePath = directory + "/" + filename;
210666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
211666ea1b28a76aeba74744148b15099254d918671Owen Lin            File dir = new File(directory);
212666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (!dir.exists()) dir.mkdirs();
213666ea1b28a76aeba74744148b15099254d918671Owen Lin            File file = new File(directory, filename);
214666ea1b28a76aeba74744148b15099254d918671Owen Lin            outputStream = new FileOutputStream(file);
215666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (source != null) {
216666ea1b28a76aeba74744148b15099254d918671Owen Lin                source.compress(CompressFormat.JPEG, 75, outputStream);
217666ea1b28a76aeba74744148b15099254d918671Owen Lin                degree[0] = 0;
218666ea1b28a76aeba74744148b15099254d918671Owen Lin            } else {
219666ea1b28a76aeba74744148b15099254d918671Owen Lin                outputStream.write(jpegData);
220666ea1b28a76aeba74744148b15099254d918671Owen Lin                degree[0] = getExifOrientation(filePath);
221666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
222666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (FileNotFoundException ex) {
223666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.w(TAG, ex);
224666ea1b28a76aeba74744148b15099254d918671Owen Lin            return null;
225666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (IOException ex) {
226666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.w(TAG, ex);
227666ea1b28a76aeba74744148b15099254d918671Owen Lin            return null;
228666ea1b28a76aeba74744148b15099254d918671Owen Lin        } finally {
229666ea1b28a76aeba74744148b15099254d918671Owen Lin            Util.closeSilently(outputStream);
230666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
231666ea1b28a76aeba74744148b15099254d918671Owen Lin
232666ea1b28a76aeba74744148b15099254d918671Owen Lin        ContentValues values = new ContentValues(7);
233666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.TITLE, title);
234666ea1b28a76aeba74744148b15099254d918671Owen Lin
235666ea1b28a76aeba74744148b15099254d918671Owen Lin        // That filename is what will be handed to Gmail when a user shares a
236666ea1b28a76aeba74744148b15099254d918671Owen Lin        // photo. Gmail gets the name of the picture attachment from the
237666ea1b28a76aeba74744148b15099254d918671Owen Lin        // "DISPLAY_NAME" field.
238666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.DISPLAY_NAME, filename);
239666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.DATE_TAKEN, dateTaken);
240666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.MIME_TYPE, "image/jpeg");
241666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.ORIENTATION, degree[0]);
242666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(Images.Media.DATA, filePath);
243666ea1b28a76aeba74744148b15099254d918671Owen Lin
244666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (location != null) {
245666ea1b28a76aeba74744148b15099254d918671Owen Lin            values.put(Images.Media.LATITUDE, location.getLatitude());
246666ea1b28a76aeba74744148b15099254d918671Owen Lin            values.put(Images.Media.LONGITUDE, location.getLongitude());
247666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
248666ea1b28a76aeba74744148b15099254d918671Owen Lin
249666ea1b28a76aeba74744148b15099254d918671Owen Lin        return cr.insert(STORAGE_URI, values);
250666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
251666ea1b28a76aeba74744148b15099254d918671Owen Lin
252666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static int getExifOrientation(String filepath) {
253666ea1b28a76aeba74744148b15099254d918671Owen Lin        int degree = 0;
254666ea1b28a76aeba74744148b15099254d918671Owen Lin        ExifInterface exif = null;
255666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
256666ea1b28a76aeba74744148b15099254d918671Owen Lin            exif = new ExifInterface(filepath);
257666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (IOException ex) {
258666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.e(TAG, "cannot read exif", ex);
259666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
260666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (exif != null) {
261666ea1b28a76aeba74744148b15099254d918671Owen Lin            int orientation = exif.getAttributeInt(
262666ea1b28a76aeba74744148b15099254d918671Owen Lin                ExifInterface.TAG_ORIENTATION, -1);
263666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (orientation != -1) {
264666ea1b28a76aeba74744148b15099254d918671Owen Lin                // We only recognize a subset of orientation tag values.
265666ea1b28a76aeba74744148b15099254d918671Owen Lin                switch(orientation) {
266666ea1b28a76aeba74744148b15099254d918671Owen Lin                    case ExifInterface.ORIENTATION_ROTATE_90:
267666ea1b28a76aeba74744148b15099254d918671Owen Lin                        degree = 90;
268666ea1b28a76aeba74744148b15099254d918671Owen Lin                        break;
269666ea1b28a76aeba74744148b15099254d918671Owen Lin                    case ExifInterface.ORIENTATION_ROTATE_180:
270666ea1b28a76aeba74744148b15099254d918671Owen Lin                        degree = 180;
271666ea1b28a76aeba74744148b15099254d918671Owen Lin                        break;
272666ea1b28a76aeba74744148b15099254d918671Owen Lin                    case ExifInterface.ORIENTATION_ROTATE_270:
273666ea1b28a76aeba74744148b15099254d918671Owen Lin                        degree = 270;
274666ea1b28a76aeba74744148b15099254d918671Owen Lin                        break;
275666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
276666ea1b28a76aeba74744148b15099254d918671Owen Lin
277666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
278666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
279666ea1b28a76aeba74744148b15099254d918671Owen Lin        return degree;
280666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
281666ea1b28a76aeba74744148b15099254d918671Owen Lin
282666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is the factory function to create an image list.
283666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static IImageList makeImageList(ContentResolver cr,
284666ea1b28a76aeba74744148b15099254d918671Owen Lin            ImageListParam param) {
285666ea1b28a76aeba74744148b15099254d918671Owen Lin        DataLocation location = param.mLocation;
286666ea1b28a76aeba74744148b15099254d918671Owen Lin        int inclusion = param.mInclusion;
287666ea1b28a76aeba74744148b15099254d918671Owen Lin        int sort = param.mSort;
288666ea1b28a76aeba74744148b15099254d918671Owen Lin        String bucketId = param.mBucketId;
289666ea1b28a76aeba74744148b15099254d918671Owen Lin        Uri singleImageUri = param.mSingleImageUri;
290666ea1b28a76aeba74744148b15099254d918671Owen Lin        boolean isEmptyImageList = param.mIsEmptyImageList;
291666ea1b28a76aeba74744148b15099254d918671Owen Lin
292666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (isEmptyImageList || cr == null) {
293666ea1b28a76aeba74744148b15099254d918671Owen Lin            return new EmptyImageList();
294666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
295666ea1b28a76aeba74744148b15099254d918671Owen Lin
296666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (singleImageUri != null) {
297666ea1b28a76aeba74744148b15099254d918671Owen Lin            return new SingleImageList(cr, singleImageUri);
298666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
299666ea1b28a76aeba74744148b15099254d918671Owen Lin
300666ea1b28a76aeba74744148b15099254d918671Owen Lin        // false ==> don't require write access
301666ea1b28a76aeba74744148b15099254d918671Owen Lin        boolean haveSdCard = hasStorage(false);
302666ea1b28a76aeba74744148b15099254d918671Owen Lin
303666ea1b28a76aeba74744148b15099254d918671Owen Lin        // use this code to merge videos and stills into the same list
304666ea1b28a76aeba74744148b15099254d918671Owen Lin        ArrayList<BaseImageList> l = new ArrayList<BaseImageList>();
305666ea1b28a76aeba74744148b15099254d918671Owen Lin
306666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (haveSdCard && location != DataLocation.INTERNAL) {
307666ea1b28a76aeba74744148b15099254d918671Owen Lin            if ((inclusion & INCLUDE_IMAGES) != 0) {
308b62254a185d04ecfe2ddc837b7e0e54f0273c478Owen Lin                l.add(new ImageList(cr, STORAGE_URI, sort, bucketId));
309666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
310666ea1b28a76aeba74744148b15099254d918671Owen Lin            if ((inclusion & INCLUDE_VIDEOS) != 0) {
311666ea1b28a76aeba74744148b15099254d918671Owen Lin                l.add(new VideoList(cr, VIDEO_STORAGE_URI, sort, bucketId));
312666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
313666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
314666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (location == DataLocation.INTERNAL || location == DataLocation.ALL) {
315666ea1b28a76aeba74744148b15099254d918671Owen Lin            if ((inclusion & INCLUDE_IMAGES) != 0) {
316666ea1b28a76aeba74744148b15099254d918671Owen Lin                l.add(new ImageList(cr,
317b62254a185d04ecfe2ddc837b7e0e54f0273c478Owen Lin                        Images.Media.INTERNAL_CONTENT_URI, sort, bucketId));
318666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
319666ea1b28a76aeba74744148b15099254d918671Owen Lin            if ((inclusion & INCLUDE_DRM_IMAGES) != 0) {
320666ea1b28a76aeba74744148b15099254d918671Owen Lin                l.add(new DrmImageList(
321666ea1b28a76aeba74744148b15099254d918671Owen Lin                        cr, DrmStore.Images.CONTENT_URI, sort, bucketId));
322666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
323666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
324666ea1b28a76aeba74744148b15099254d918671Owen Lin
325666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Optimization: If some of the lists are empty, remove them.
326666ea1b28a76aeba74744148b15099254d918671Owen Lin        // If there is only one remaining list, return it directly.
327666ea1b28a76aeba74744148b15099254d918671Owen Lin        Iterator<BaseImageList> iter = l.iterator();
328666ea1b28a76aeba74744148b15099254d918671Owen Lin        while (iter.hasNext()) {
329666ea1b28a76aeba74744148b15099254d918671Owen Lin            BaseImageList sublist = iter.next();
330666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (sublist.isEmpty()) {
331666ea1b28a76aeba74744148b15099254d918671Owen Lin                sublist.close();
332666ea1b28a76aeba74744148b15099254d918671Owen Lin                iter.remove();
333666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
334666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
335666ea1b28a76aeba74744148b15099254d918671Owen Lin
336666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (l.size() == 1) {
337666ea1b28a76aeba74744148b15099254d918671Owen Lin            BaseImageList list = l.get(0);
338666ea1b28a76aeba74744148b15099254d918671Owen Lin            return list;
339666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
340666ea1b28a76aeba74744148b15099254d918671Owen Lin
341666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageListUber uber = new ImageListUber(
342666ea1b28a76aeba74744148b15099254d918671Owen Lin                l.toArray(new IImageList[l.size()]), sort);
343666ea1b28a76aeba74744148b15099254d918671Owen Lin        return uber;
344666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
345666ea1b28a76aeba74744148b15099254d918671Owen Lin
346666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is a convenience function to create an image list from a Uri.
347666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static IImageList makeImageList(ContentResolver cr, Uri uri,
348666ea1b28a76aeba74744148b15099254d918671Owen Lin            int sort) {
349666ea1b28a76aeba74744148b15099254d918671Owen Lin        String uriString = (uri != null) ? uri.toString() : "";
350666ea1b28a76aeba74744148b15099254d918671Owen Lin
351666ea1b28a76aeba74744148b15099254d918671Owen Lin        // TODO: we need to figure out whether we're viewing
352666ea1b28a76aeba74744148b15099254d918671Owen Lin        // DRM images in a better way.  Is there a constant
353666ea1b28a76aeba74744148b15099254d918671Owen Lin        // for content://drm somewhere??
354666ea1b28a76aeba74744148b15099254d918671Owen Lin
355666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (uriString.startsWith("content://drm")) {
356666ea1b28a76aeba74744148b15099254d918671Owen Lin            return makeImageList(cr, DataLocation.ALL, INCLUDE_DRM_IMAGES, sort,
357666ea1b28a76aeba74744148b15099254d918671Owen Lin                    null);
358666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (uriString.startsWith("content://media/external/video")) {
359666ea1b28a76aeba74744148b15099254d918671Owen Lin            return makeImageList(cr, DataLocation.EXTERNAL, INCLUDE_VIDEOS,
360666ea1b28a76aeba74744148b15099254d918671Owen Lin                    sort, null);
361666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (isSingleImageMode(uriString)) {
362666ea1b28a76aeba74744148b15099254d918671Owen Lin            return makeSingleImageList(cr, uri);
363666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
364666ea1b28a76aeba74744148b15099254d918671Owen Lin            String bucketId = uri.getQueryParameter("bucketId");
365666ea1b28a76aeba74744148b15099254d918671Owen Lin            return makeImageList(cr, DataLocation.ALL, INCLUDE_IMAGES, sort,
366666ea1b28a76aeba74744148b15099254d918671Owen Lin                    bucketId);
367666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
368666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
369666ea1b28a76aeba74744148b15099254d918671Owen Lin
370666ea1b28a76aeba74744148b15099254d918671Owen Lin    static boolean isSingleImageMode(String uriString) {
371666ea1b28a76aeba74744148b15099254d918671Owen Lin        return !uriString.startsWith(
372666ea1b28a76aeba74744148b15099254d918671Owen Lin                MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())
373666ea1b28a76aeba74744148b15099254d918671Owen Lin                && !uriString.startsWith(
374666ea1b28a76aeba74744148b15099254d918671Owen Lin                MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString());
375666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
376666ea1b28a76aeba74744148b15099254d918671Owen Lin
377666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static class EmptyImageList implements IImageList {
378666ea1b28a76aeba74744148b15099254d918671Owen Lin        public void close() {
379666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
380666ea1b28a76aeba74744148b15099254d918671Owen Lin
381666ea1b28a76aeba74744148b15099254d918671Owen Lin        public HashMap<String, String> getBucketIds() {
382666ea1b28a76aeba74744148b15099254d918671Owen Lin            return new HashMap<String, String>();
383666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
384666ea1b28a76aeba74744148b15099254d918671Owen Lin
385666ea1b28a76aeba74744148b15099254d918671Owen Lin        public int getCount() {
386666ea1b28a76aeba74744148b15099254d918671Owen Lin            return 0;
387666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
388666ea1b28a76aeba74744148b15099254d918671Owen Lin
389666ea1b28a76aeba74744148b15099254d918671Owen Lin        public boolean isEmpty() {
390666ea1b28a76aeba74744148b15099254d918671Owen Lin            return true;
391666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
392666ea1b28a76aeba74744148b15099254d918671Owen Lin
393666ea1b28a76aeba74744148b15099254d918671Owen Lin        public IImage getImageAt(int i) {
394666ea1b28a76aeba74744148b15099254d918671Owen Lin            return null;
395666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
396666ea1b28a76aeba74744148b15099254d918671Owen Lin
397666ea1b28a76aeba74744148b15099254d918671Owen Lin        public IImage getImageForUri(Uri uri) {
398666ea1b28a76aeba74744148b15099254d918671Owen Lin            return null;
399666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
400666ea1b28a76aeba74744148b15099254d918671Owen Lin
401666ea1b28a76aeba74744148b15099254d918671Owen Lin        public boolean removeImage(IImage image) {
402666ea1b28a76aeba74744148b15099254d918671Owen Lin            return false;
403666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
404666ea1b28a76aeba74744148b15099254d918671Owen Lin
405666ea1b28a76aeba74744148b15099254d918671Owen Lin        public boolean removeImageAt(int i) {
406666ea1b28a76aeba74744148b15099254d918671Owen Lin            return false;
407666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
408666ea1b28a76aeba74744148b15099254d918671Owen Lin
409666ea1b28a76aeba74744148b15099254d918671Owen Lin        public int getImageIndex(IImage image) {
410666ea1b28a76aeba74744148b15099254d918671Owen Lin            throw new UnsupportedOperationException();
411666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
412666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
413666ea1b28a76aeba74744148b15099254d918671Owen Lin
414666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static ImageListParam getImageListParam(DataLocation location,
415666ea1b28a76aeba74744148b15099254d918671Owen Lin         int inclusion, int sort, String bucketId) {
416666ea1b28a76aeba74744148b15099254d918671Owen Lin         ImageListParam param = new ImageListParam();
417666ea1b28a76aeba74744148b15099254d918671Owen Lin         param.mLocation = location;
418666ea1b28a76aeba74744148b15099254d918671Owen Lin         param.mInclusion = inclusion;
419666ea1b28a76aeba74744148b15099254d918671Owen Lin         param.mSort = sort;
420666ea1b28a76aeba74744148b15099254d918671Owen Lin         param.mBucketId = bucketId;
421666ea1b28a76aeba74744148b15099254d918671Owen Lin         return param;
422666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
423666ea1b28a76aeba74744148b15099254d918671Owen Lin
424666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static ImageListParam getSingleImageListParam(Uri uri) {
425666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageListParam param = new ImageListParam();
426666ea1b28a76aeba74744148b15099254d918671Owen Lin        param.mSingleImageUri = uri;
427666ea1b28a76aeba74744148b15099254d918671Owen Lin        return param;
428666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
429666ea1b28a76aeba74744148b15099254d918671Owen Lin
430666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static ImageListParam getEmptyImageListParam() {
431666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageListParam param = new ImageListParam();
432666ea1b28a76aeba74744148b15099254d918671Owen Lin        param.mIsEmptyImageList = true;
433666ea1b28a76aeba74744148b15099254d918671Owen Lin        return param;
434666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
435666ea1b28a76aeba74744148b15099254d918671Owen Lin
436666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static IImageList makeImageList(ContentResolver cr,
437666ea1b28a76aeba74744148b15099254d918671Owen Lin            DataLocation location, int inclusion, int sort, String bucketId) {
438666ea1b28a76aeba74744148b15099254d918671Owen Lin        ImageListParam param = getImageListParam(location, inclusion, sort,
439666ea1b28a76aeba74744148b15099254d918671Owen Lin                bucketId);
440666ea1b28a76aeba74744148b15099254d918671Owen Lin        return makeImageList(cr, param);
441666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
442666ea1b28a76aeba74744148b15099254d918671Owen Lin
443666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static IImageList makeEmptyImageList() {
444666ea1b28a76aeba74744148b15099254d918671Owen Lin        return makeImageList(null, getEmptyImageListParam());
445666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
446666ea1b28a76aeba74744148b15099254d918671Owen Lin
447666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static IImageList  makeSingleImageList(ContentResolver cr, Uri uri) {
448666ea1b28a76aeba74744148b15099254d918671Owen Lin        return makeImageList(cr, getSingleImageListParam(uri));
449666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
450666ea1b28a76aeba74744148b15099254d918671Owen Lin
451666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static boolean checkFsWritable() {
452666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Create a temporary file to see whether a volume is really writeable.
453666ea1b28a76aeba74744148b15099254d918671Owen Lin        // It's important not to put it in the root directory which may have a
454666ea1b28a76aeba74744148b15099254d918671Owen Lin        // limit on the number of files.
455666ea1b28a76aeba74744148b15099254d918671Owen Lin        String directoryName =
456666ea1b28a76aeba74744148b15099254d918671Owen Lin                Environment.getExternalStorageDirectory().toString() + "/DCIM";
457666ea1b28a76aeba74744148b15099254d918671Owen Lin        File directory = new File(directoryName);
458666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (!directory.isDirectory()) {
459666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (!directory.mkdirs()) {
460666ea1b28a76aeba74744148b15099254d918671Owen Lin                return false;
461666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
462666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
463666ea1b28a76aeba74744148b15099254d918671Owen Lin        File f = new File(directoryName, ".probe");
464666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
465666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Remove stale file if any
466666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (f.exists()) {
467666ea1b28a76aeba74744148b15099254d918671Owen Lin                f.delete();
468666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
469666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (!f.createNewFile()) {
470666ea1b28a76aeba74744148b15099254d918671Owen Lin                return false;
471666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
472666ea1b28a76aeba74744148b15099254d918671Owen Lin            f.delete();
473666ea1b28a76aeba74744148b15099254d918671Owen Lin            return true;
474666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (IOException ex) {
475666ea1b28a76aeba74744148b15099254d918671Owen Lin            return false;
476666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
477666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
478666ea1b28a76aeba74744148b15099254d918671Owen Lin
479666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean hasStorage() {
480666ea1b28a76aeba74744148b15099254d918671Owen Lin        return hasStorage(true);
481666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
482666ea1b28a76aeba74744148b15099254d918671Owen Lin
483666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean hasStorage(boolean requireWriteAccess) {
484666ea1b28a76aeba74744148b15099254d918671Owen Lin        String state = Environment.getExternalStorageState();
485666ea1b28a76aeba74744148b15099254d918671Owen Lin
486666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (Environment.MEDIA_MOUNTED.equals(state)) {
487666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (requireWriteAccess) {
488666ea1b28a76aeba74744148b15099254d918671Owen Lin                boolean writable = checkFsWritable();
489666ea1b28a76aeba74744148b15099254d918671Owen Lin                return writable;
490666ea1b28a76aeba74744148b15099254d918671Owen Lin            } else {
491666ea1b28a76aeba74744148b15099254d918671Owen Lin                return true;
492666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
493666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (!requireWriteAccess
494666ea1b28a76aeba74744148b15099254d918671Owen Lin                && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
495666ea1b28a76aeba74744148b15099254d918671Owen Lin            return true;
496666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
497666ea1b28a76aeba74744148b15099254d918671Owen Lin        return false;
498666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
499666ea1b28a76aeba74744148b15099254d918671Owen Lin
500666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static Cursor query(ContentResolver resolver, Uri uri,
501666ea1b28a76aeba74744148b15099254d918671Owen Lin            String[] projection, String selection, String[] selectionArgs,
502666ea1b28a76aeba74744148b15099254d918671Owen Lin            String sortOrder) {
503666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
504666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (resolver == null) {
505666ea1b28a76aeba74744148b15099254d918671Owen Lin                return null;
506666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
507666ea1b28a76aeba74744148b15099254d918671Owen Lin            return resolver.query(
508666ea1b28a76aeba74744148b15099254d918671Owen Lin                    uri, projection, selection, selectionArgs, sortOrder);
509666ea1b28a76aeba74744148b15099254d918671Owen Lin         } catch (UnsupportedOperationException ex) {
510666ea1b28a76aeba74744148b15099254d918671Owen Lin            return null;
511666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
512666ea1b28a76aeba74744148b15099254d918671Owen Lin
513666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
514666ea1b28a76aeba74744148b15099254d918671Owen Lin
515666ea1b28a76aeba74744148b15099254d918671Owen Lin    public static boolean isMediaScannerScanning(ContentResolver cr) {
516666ea1b28a76aeba74744148b15099254d918671Owen Lin        boolean result = false;
517666ea1b28a76aeba74744148b15099254d918671Owen Lin        Cursor cursor = query(cr, MediaStore.getMediaScannerUri(),
518666ea1b28a76aeba74744148b15099254d918671Owen Lin                new String [] {MediaStore.MEDIA_SCANNER_VOLUME},
519666ea1b28a76aeba74744148b15099254d918671Owen Lin                null, null, null);
520666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (cursor != null) {
521666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (cursor.getCount() == 1) {
522666ea1b28a76aeba74744148b15099254d918671Owen Lin                cursor.moveToFirst();
523666ea1b28a76aeba74744148b15099254d918671Owen Lin                result = "external".equals(cursor.getString(0));
524666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
525666ea1b28a76aeba74744148b15099254d918671Owen Lin            cursor.close();
526666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
527666ea1b28a76aeba74744148b15099254d918671Owen Lin
528666ea1b28a76aeba74744148b15099254d918671Owen Lin        return result;
529666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
530666ea1b28a76aeba74744148b15099254d918671Owen Lin}
531