1c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount/*
2c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * Copyright (C) 2013 The Android Open Source Project
3c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount *
4c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * Licensed under the Apache License, Version 2.0 (the "License");
5c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * you may not use this file except in compliance with the License.
6c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * You may obtain a copy of the License at
7c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount *
8c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount *      http://www.apache.org/licenses/LICENSE-2.0
9c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount *
10c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * Unless required by applicable law or agreed to in writing, software
11c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * distributed under the License is distributed on an "AS IS" BASIS,
12c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * See the License for the specific language governing permissions and
14c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * limitations under the License.
15c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount */
16c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountpackage com.android.photos.data;
17c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
185139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mountimport android.content.ContentResolver;
19aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mountimport android.content.ContentUris;
20c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.content.ContentValues;
215139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mountimport android.content.Context;
22c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.content.UriMatcher;
23c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.Cursor;
24c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.DatabaseUtils;
25c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.sqlite.SQLiteDatabase;
26c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.sqlite.SQLiteOpenHelper;
27135c2e576f3dfea954ba628942c55adcb35a7cf6George Mountimport android.database.sqlite.SQLiteQueryBuilder;
282f5a064980ad79e88616ba124268e4d7298c68a5George Mountimport android.media.ExifInterface;
29c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.net.Uri;
30c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.os.CancellationSignal;
31c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.provider.BaseColumns;
32c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
33091314b7ea73e774ce96c981bd7007c94ad80e30George Mountimport com.android.gallery3d.common.ApiHelper;
34091314b7ea73e774ce96c981bd7007c94ad80e30George Mount
35c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport java.util.List;
36c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
37c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount/**
38c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * A provider that gives access to photo and video information for media stored
39c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * on the server. Only media that is or will be put on the server will be
40c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * accessed by this provider. Use Photos.CONTENT_URI to query all photos and
41c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * videos. Use Albums.CONTENT_URI to query all albums. Use Metadata.CONTENT_URI
42c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * to query metadata about a photo or video, based on the ID of the media. Use
43c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * ImageCache.THUMBNAIL_CONTENT_URI, ImageCache.PREVIEW_CONTENT_URI, or
44c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * ImageCache.ORIGINAL_CONTENT_URI to query the path of the thumbnail, preview,
45c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * or original-sized image respectfully. <br/>
46c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * To add or update metadata, use the update function rather than insert. All
47c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * values for the metadata must be in the ContentValues, even if they are also
48c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * in the selection. The selection and selectionArgs are not used when updating
49c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * metadata. If the metadata values are null, the row will be deleted.
50c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount */
515139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mountpublic class PhotoProvider extends SQLiteContentProvider {
52c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @SuppressWarnings("unused")
53c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static final String TAG = PhotoProvider.class.getSimpleName();
54135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
55135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected static final String DB_NAME = "photo.db";
56135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public static final String AUTHORITY = PhotoProviderAuthority.AUTHORITY;
57c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    static final Uri BASE_CONTENT_URI = new Uri.Builder().scheme("content").authority(AUTHORITY)
58c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            .build();
59c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
60135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    // Used to allow mocking out the change notification because
61135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    // MockContextResolver disallows system-wide notification.
62135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public static interface ChangeNotification {
635139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        void notifyChange(Uri uri, boolean syncToNetwork);
64135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    }
65135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
66c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
672f5a064980ad79e88616ba124268e4d7298c68a5George Mount     * Contains columns that can be accessed via Accounts.CONTENT_URI
68c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
692f5a064980ad79e88616ba124268e4d7298c68a5George Mount    public static interface Accounts extends BaseColumns {
70c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
712f5a064980ad79e88616ba124268e4d7298c68a5George Mount         * Internal database table used for account information
72c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
732f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String TABLE = "accounts";
74c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
752f5a064980ad79e88616ba124268e4d7298c68a5George Mount         * Content URI for account information
76c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
77c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
78c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
792f5a064980ad79e88616ba124268e4d7298c68a5George Mount         * User name for this account.
80c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
812f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String ACCOUNT_NAME = "name";
822f5a064980ad79e88616ba124268e4d7298c68a5George Mount    }
832f5a064980ad79e88616ba124268e4d7298c68a5George Mount
842f5a064980ad79e88616ba124268e4d7298c68a5George Mount    /**
852f5a064980ad79e88616ba124268e4d7298c68a5George Mount     * Contains columns that can be accessed via Photos.CONTENT_URI.
862f5a064980ad79e88616ba124268e4d7298c68a5George Mount     */
872f5a064980ad79e88616ba124268e4d7298c68a5George Mount    public static interface Photos extends BaseColumns {
88d4681a3c9d417970a9602112bd83f921ac16af96George Mount        /**
89d4681a3c9d417970a9602112bd83f921ac16af96George Mount         * The image_type query parameter required for requesting a specific
90d4681a3c9d417970a9602112bd83f921ac16af96George Mount         * size of image.
91d4681a3c9d417970a9602112bd83f921ac16af96George Mount         */
92d4681a3c9d417970a9602112bd83f921ac16af96George Mount        public static final String MEDIA_SIZE_QUERY_PARAMETER = "media_size";
93d4681a3c9d417970a9602112bd83f921ac16af96George Mount
942f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Internal database table used for basic photo information. */
95693a5b7a18066d4757d49a44214356a3dd9f61a0Mangesh Ghiware        public static final String TABLE = "photos";
962f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Content URI for basic photo and video information. */
972f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
982f5a064980ad79e88616ba124268e4d7298c68a5George Mount
992f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Long foreign key to Accounts._ID */
1002f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String ACCOUNT_ID = "account_id";
1012f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Column name for the width of the original image. Integer value. */
102c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String WIDTH = "width";
1032f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Column name for the height of the original image. Integer value. */
104c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String HEIGHT = "height";
105c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
106c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the date that the original image was taken. Long
107c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * value indicating the milliseconds since epoch in the GMT time zone.
108c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
109c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String DATE_TAKEN = "date_taken";
110c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
111c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name indicating the long value of the album id that this image
112c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * resides in. Will be NULL if it it has not been uploaded to the
113c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * server.
114c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
115c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String ALBUM_ID = "album_id";
1162f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The column name for the mime-type String. */
1172f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String MIME_TYPE = "mime_type";
1182f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The title of the photo. String value. */
1192f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String TITLE = "title";
1202f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The date the photo entry was last updated. Long value. */
1212f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String DATE_MODIFIED = "date_modified";
122c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
1232f5a064980ad79e88616ba124268e4d7298c68a5George Mount         * The rotation of the photo in degrees, if rotation has not already
1242f5a064980ad79e88616ba124268e4d7298c68a5George Mount         * been applied. Integer value.
125c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
1262f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String ROTATION = "rotation";
127c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
128c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
129c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
130c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns and Uri for accessing album information.
131c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
132c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface Albums extends BaseColumns {
1332f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Internal database table used album information. */
134693a5b7a18066d4757d49a44214356a3dd9f61a0Mangesh Ghiware        public static final String TABLE = "albums";
1352f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Content URI for album information. */
136c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
1372f5a064980ad79e88616ba124268e4d7298c68a5George Mount
1382f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Long foreign key to Accounts._ID */
1392f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String ACCOUNT_ID = "account_id";
1402f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Parent directory or null if this is in the root. */
1412f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String PARENT_ID = "parent_id";
142b2a646658c87378b681d85a130db705a39d07171Mangesh Ghiware        /** The type of album. Non-null, if album is auto-generated. String value. */
143b2a646658c87378b681d85a130db705a39d07171Mangesh Ghiware        public static final String ALBUM_TYPE = "album_type";
144c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
145c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the visibility level of the album. Can be any of the
146c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * VISIBILITY_* values.
147c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
148c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String VISIBILITY = "visibility";
1492f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The user-specified location associated with the album. String value. */
1502f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String LOCATION_STRING = "location_string";
1512f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The title of the album. String value. */
1522f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String TITLE = "title";
1532f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** A short summary of the contents of the album. String value. */
1542f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String SUMMARY = "summary";
1552f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The date the album was created. Long value */
1562f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String DATE_PUBLISHED = "date_published";
1572f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The date the album entry was last updated. Long value. */
1582f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String DATE_MODIFIED = "date_modified";
159c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
160c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // Privacy values for Albums.VISIBILITY
161c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_PRIVATE = 1;
162c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_SHARED = 2;
163c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_PUBLIC = 3;
164c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
165c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
166c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
167c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns and Uri for accessing photo and video metadata
168c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
169c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface Metadata extends BaseColumns {
1702f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Internal database table used metadata information. */
171c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String TABLE = "metadata";
1722f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Content URI for photo and video metadata. */
173c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
1742f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Foreign key to photo_id. Long value. */
175c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String PHOTO_ID = "photo_id";
1762f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Metadata key. String value */
177c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String KEY = "key";
178c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
179c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Metadata value. Type is based on key.
180c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
181c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String VALUE = "value";
1822f5a064980ad79e88616ba124268e4d7298c68a5George Mount
1832f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** A short summary of the photo. String value. */
1842f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_SUMMARY = "summary";
1852f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The date the photo was added. Long value. */
1862f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_PUBLISHED = "date_published";
1872f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The date the photo was last updated. Long value. */
1882f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_DATE_UPDATED = "date_updated";
1892f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The size of the photo is bytes. Integer value. */
1902f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_SIZE_IN_BTYES = "size";
1912f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The latitude associated with the photo. Double value. */
1922f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_LATITUDE = "latitude";
1932f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The longitude associated with the photo. Double value. */
1942f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_LONGITUDE = "longitude";
1952f5a064980ad79e88616ba124268e4d7298c68a5George Mount
1962f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The make of the camera used. String value. */
1972f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_MAKE = ExifInterface.TAG_MAKE;
1982f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The model of the camera used. String value. */
1992f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_MODEL = ExifInterface.TAG_MODEL;;
2002f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The exposure time used. Float value. */
2012f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_EXPOSURE = ExifInterface.TAG_EXPOSURE_TIME;
2022f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** Whether the flash was used. Boolean value. */
2032f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_FLASH = ExifInterface.TAG_FLASH;
2042f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The focal length used. Float value. */
2052f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_FOCAL_LENGTH = ExifInterface.TAG_FOCAL_LENGTH;
2062f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The fstop value used. Float value. */
2072f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_FSTOP = ExifInterface.TAG_APERTURE;
2082f5a064980ad79e88616ba124268e4d7298c68a5George Mount        /** The ISO equivalent value used. Integer value. */
2092f5a064980ad79e88616ba124268e4d7298c68a5George Mount        public static final String KEY_EXIF_ISO = ExifInterface.TAG_ISO;
210c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
211c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
212c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    // SQL used within this class.
213c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE_ID = BaseColumns._ID + " = ?";
214c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE_METADATA_ID = Metadata.PHOTO_ID + " = ? AND "
215c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Metadata.KEY + " = ?";
216c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
217c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_ALBUM_ID = "SELECT " + Albums._ID + " FROM "
218c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Albums.TABLE;
219c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_PHOTO_ID = "SELECT " + Photos._ID + " FROM "
220c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Photos.TABLE;
221c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_PHOTO_COUNT = "SELECT COUNT(*) FROM " + Photos.TABLE;
222c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String DELETE_PHOTOS = "DELETE FROM " + Photos.TABLE;
223c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String DELETE_METADATA = "DELETE FROM " + Metadata.TABLE;
224c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_METADATA_COUNT = "SELECT COUNT(*) FROM " + Metadata.TABLE;
225c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE = " WHERE ";
226c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String IN = " IN ";
227c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String NESTED_SELECT_START = "(";
228c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String NESTED_SELECT_END = ")";
229ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount    protected static final String[] PROJECTION_COUNT = {
230ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount        "COUNT(*)"
231ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount    };
232c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
233c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
234c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * For selecting the mime-type for an image.
235c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
236c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static final String[] PROJECTION_MIME_TYPE = {
237c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        Photos.MIME_TYPE,
238c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    };
239c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
24009bfc1d566621498d08903559ae707161a701571George Mount    protected static final String[] BASE_COLUMNS_ID = {
241135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        BaseColumns._ID,
242135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    };
243135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
244135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected ChangeNotification mNotifier = null;
245c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
246c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
247c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_PHOTO = 1;
248c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_PHOTO_ID = 2;
249c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_ALBUM = 3;
250c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_ALBUM_ID = 4;
251c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_METADATA = 5;
252c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_METADATA_ID = 6;
253d4681a3c9d417970a9602112bd83f921ac16af96George Mount    protected static final int MATCH_ACCOUNT = 7;
254d4681a3c9d417970a9602112bd83f921ac16af96George Mount    protected static final int MATCH_ACCOUNT_ID = 8;
255c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
256c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    static {
257c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Photos.TABLE, MATCH_PHOTO);
258c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against Photos._ID
259c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Photos.TABLE + "/#", MATCH_PHOTO_ID);
260c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Albums.TABLE, MATCH_ALBUM);
261c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against Albums._ID
262c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Albums.TABLE + "/#", MATCH_ALBUM_ID);
263c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Metadata.TABLE, MATCH_METADATA);
264c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against metadata/<Metadata._ID>
265c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Metadata.TABLE + "/#", MATCH_METADATA_ID);
266dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware        sUriMatcher.addURI(AUTHORITY, Accounts.TABLE, MATCH_ACCOUNT);
267dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware        // match against Accounts._ID
268dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware        sUriMatcher.addURI(AUTHORITY, Accounts.TABLE + "/#", MATCH_ACCOUNT_ID);
269c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
270c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
271c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
2725139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs,
2735139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            boolean callerIsSyncAdapter) {
274c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
275c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selection = addIdToSelection(match, selection);
276c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
2778324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        return deleteCascade(uri, match, selection, selectionArgs);
278c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
279c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
280c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
281c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public String getType(Uri uri) {
282c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        Cursor cursor = query(uri, PROJECTION_MIME_TYPE, null, null, null);
283c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String mimeType = null;
284c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (cursor.moveToNext()) {
285c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            mimeType = cursor.getString(0);
286c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
287c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        cursor.close();
288c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return mimeType;
289c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
290c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
291c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
2925139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    public Uri insertInTransaction(Uri uri, ContentValues values, boolean callerIsSyncAdapter) {
293aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        int match = matchUri(uri);
294aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        validateMatchTable(match);
295aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        String table = getTableFromMatch(match, uri);
2965139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
297aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        Uri insertedUri = null;
2985139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        long id = db.insert(table, null, values);
2995139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        if (id != -1) {
3005139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            // uri already matches the table.
3015139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            insertedUri = ContentUris.withAppendedId(uri, id);
3025139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            postNotifyUri(insertedUri);
303aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        }
304aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        return insertedUri;
305c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
306c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
307c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
308c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
309c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String sortOrder) {
310c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return query(uri, projection, selection, selectionArgs, sortOrder, null);
311c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
312c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
313c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
314c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
315c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String sortOrder, CancellationSignal cancellationSignal) {
316ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount        projection = replaceCount(projection);
317c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
318c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selection = addIdToSelection(match, selection);
319c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
320c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table = getTableFromMatch(match, uri);
321835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck        Cursor c = query(table, projection, selection, selectionArgs, sortOrder, cancellationSignal);
322835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck        if (c != null) {
323835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck            c.setNotificationUri(getContext().getContentResolver(), uri);
324835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck        }
325835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck        return c;
326c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
327c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
328c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
3295139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    public int updateInTransaction(Uri uri, ContentValues values, String selection,
3305139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            String[] selectionArgs, boolean callerIsSyncAdapter) {
331c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
332c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int rowsUpdated = 0;
3335139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
3345139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        if (match == MATCH_METADATA) {
3355139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            rowsUpdated = modifyMetadata(db, values);
3365139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        } else {
3375139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            selection = addIdToSelection(match, selection);
3385139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
3395139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            String table = getTableFromMatch(match, uri);
3405139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            rowsUpdated = db.update(table, values, selection, selectionArgs);
341c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
3425139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        postNotifyUri(uri);
343c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return rowsUpdated;
344c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
345c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
346135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public void setMockNotification(ChangeNotification notification) {
347135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        mNotifier = notification;
348135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    }
349135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
350c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String addIdToSelection(int match, String selection) {
351c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String where;
352c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
353c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
354c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
355c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
356c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                where = WHERE_ID;
357c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
358c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
359c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                return selection;
360c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
361c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.concatenateWhere(selection, where);
362c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
363c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
364c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String[] addIdToSelectionArgs(int match, Uri uri, String[] selectionArgs) {
365c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String[] whereArgs;
366c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
367c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
368c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
369c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
370c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                whereArgs = new String[] {
371c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                    uri.getPathSegments().get(1),
372c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                };
373c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
374c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
375c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                return selectionArgs;
376c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
377c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.appendSelectionArgs(selectionArgs, whereArgs);
378c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
379c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
380c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String[] addMetadataKeysToSelectionArgs(String[] selectionArgs, Uri uri) {
381c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        List<String> segments = uri.getPathSegments();
382c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String[] additionalArgs = {
383c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                segments.get(1),
384c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                segments.get(2),
385c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        };
386c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
387c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.appendSelectionArgs(selectionArgs, additionalArgs);
388c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
389c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
390c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String getTableFromMatch(int match, Uri uri) {
391c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table;
392c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
393c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO:
394c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
395c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Photos.TABLE;
396c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
397c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM:
398c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
399c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Albums.TABLE;
400c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
401c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA:
402c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
403c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Metadata.TABLE;
404c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
405dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware            case MATCH_ACCOUNT:
406dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware            case MATCH_ACCOUNT_ID:
407dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware                table = Accounts.TABLE;
408dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware                break;
409c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
410c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                throw unknownUri(uri);
411c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
412c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return table;
413c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
414c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
4155139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    @Override
4165139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    public SQLiteOpenHelper getDatabaseHelper(Context context) {
4175139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount        return new PhotoDatabase(context, DB_NAME);
418c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
419c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
420c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private int modifyMetadata(SQLiteDatabase db, ContentValues values) {
421c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int rowCount;
422c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (values.get(Metadata.VALUE) == null) {
423aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            String[] selectionArgs = {
424aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount                    values.getAsString(Metadata.PHOTO_ID), values.getAsString(Metadata.KEY),
425aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            };
426c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            rowCount = db.delete(Metadata.TABLE, WHERE_METADATA_ID, selectionArgs);
427c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        } else {
428aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            long rowId = db.replace(Metadata.TABLE, null, values);
429aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            rowCount = (rowId == -1) ? 0 : 1;
430c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
431c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return rowCount;
432c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
433c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
434c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private int matchUri(Uri uri) {
435c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = sUriMatcher.match(uri);
436c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (match == UriMatcher.NO_MATCH) {
437c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            throw unknownUri(uri);
438c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
439c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return match;
440c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
441c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
4425139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    @Override
4435139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount    protected void notifyChange(ContentResolver resolver, Uri uri, boolean syncToNetwork) {
444135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        if (mNotifier != null) {
4455139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            mNotifier.notifyChange(uri, syncToNetwork);
446135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        } else {
447835a0d50318e9cd61bbbd834e36ddda4cff9c59dJohn Reck            super.notifyChange(resolver, uri, syncToNetwork);
448135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        }
449c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
450c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
451c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static IllegalArgumentException unknownUri(Uri uri) {
452c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return new IllegalArgumentException("Unknown Uri format: " + uri);
453c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
454c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
455135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected static String nestWhere(String matchColumn, String table, String nestedWhere) {
456135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        String query = SQLiteQueryBuilder.buildQueryString(false, table, BASE_COLUMNS_ID,
457135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount                nestedWhere, null, null, null, null);
458135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        return matchColumn + IN + NESTED_SELECT_START + query + NESTED_SELECT_END;
459c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
460c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
4618324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    protected static String metadataSelectionFromPhotos(String where) {
4628324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        return nestWhere(Metadata.PHOTO_ID, Photos.TABLE, where);
4638324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    }
4648324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount
4658324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    protected static String photoSelectionFromAlbums(String where) {
4668324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        return nestWhere(Photos.ALBUM_ID, Albums.TABLE, where);
4678324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    }
4688324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount
4698324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    protected static String photoSelectionFromAccounts(String where) {
4708324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        return nestWhere(Photos.ACCOUNT_ID, Accounts.TABLE, where);
4718324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    }
4728324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount
4738324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    protected static String albumSelectionFromAccounts(String where) {
4748324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        return nestWhere(Albums.ACCOUNT_ID, Accounts.TABLE, where);
4758324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    }
4768324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount
4778324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount    protected int deleteCascade(Uri uri, int match, String selection, String[] selectionArgs) {
478c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
479c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO:
48056c42ad3265ceac0674e6a4c00800336101a230cGeorge Mount            case MATCH_PHOTO_ID:
4818324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                deleteCascade(Metadata.CONTENT_URI, MATCH_METADATA,
4828324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                        metadataSelectionFromPhotos(selection), selectionArgs);
483c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
484c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM:
48556c42ad3265ceac0674e6a4c00800336101a230cGeorge Mount            case MATCH_ALBUM_ID:
4868324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                deleteCascade(Photos.CONTENT_URI, MATCH_PHOTO,
4878324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                        photoSelectionFromAlbums(selection), selectionArgs);
488c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
48956c42ad3265ceac0674e6a4c00800336101a230cGeorge Mount            case MATCH_ACCOUNT:
49056c42ad3265ceac0674e6a4c00800336101a230cGeorge Mount            case MATCH_ACCOUNT_ID:
4918324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                deleteCascade(Photos.CONTENT_URI, MATCH_PHOTO,
4928324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                        photoSelectionFromAccounts(selection), selectionArgs);
4938324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                deleteCascade(Albums.CONTENT_URI, MATCH_ALBUM,
4948324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount                        albumSelectionFromAccounts(selection), selectionArgs);
49556c42ad3265ceac0674e6a4c00800336101a230cGeorge Mount                break;
496c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
4978324b3355817e8f6d08ac0b1f7349926df8a9bc7George Mount        SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
498c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table = getTableFromMatch(match, uri);
499135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        int deleted = db.delete(table, selection, selectionArgs);
500135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        if (deleted > 0) {
5015139ee00d28c3f694df74f0ccf13cec402707aeaGeorge Mount            postNotifyUri(uri);
502c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
503135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        return deleted;
504c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
505c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
506aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount    private static void validateMatchTable(int match) {
507aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        switch (match) {
508aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            case MATCH_PHOTO:
509aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            case MATCH_ALBUM:
510aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            case MATCH_METADATA:
511dc32aaf95fd6925796474688c24704b3265a1ae7Mangesh Ghiware            case MATCH_ACCOUNT:
512aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount                break;
513aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount            default:
514aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount                throw new IllegalArgumentException("Operation not allowed on an existing row.");
515aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount        }
516aebb3b012aef838001c5f9e6adfa4bbcc7bb6569George Mount    }
517091314b7ea73e774ce96c981bd7007c94ad80e30George Mount
518091314b7ea73e774ce96c981bd7007c94ad80e30George Mount    protected Cursor query(String table, String[] columns, String selection,
519091314b7ea73e774ce96c981bd7007c94ad80e30George Mount            String[] selectionArgs, String orderBy, CancellationSignal cancellationSignal) {
520091314b7ea73e774ce96c981bd7007c94ad80e30George Mount        SQLiteDatabase db = getDatabaseHelper().getReadableDatabase();
521091314b7ea73e774ce96c981bd7007c94ad80e30George Mount        if (ApiHelper.HAS_CANCELLATION_SIGNAL) {
522091314b7ea73e774ce96c981bd7007c94ad80e30George Mount            return db.query(false, table, columns, selection, selectionArgs, null, null,
523091314b7ea73e774ce96c981bd7007c94ad80e30George Mount                    orderBy, null, cancellationSignal);
524091314b7ea73e774ce96c981bd7007c94ad80e30George Mount        } else {
525091314b7ea73e774ce96c981bd7007c94ad80e30George Mount            return db.query(table, columns, selection, selectionArgs, null, null, orderBy);
526091314b7ea73e774ce96c981bd7007c94ad80e30George Mount        }
527091314b7ea73e774ce96c981bd7007c94ad80e30George Mount    }
528ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount
529ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount    protected static String[] replaceCount(String[] projection) {
530ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount        if (projection != null && projection.length == 1
531ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount                && BaseColumns._COUNT.equals(projection[0])) {
532ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount            return PROJECTION_COUNT;
533ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount        }
534ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount        return projection;
535ba1d7caf633631e3195e3938a39b86efd820869aGeorge Mount    }
536c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount}
537