PhotoProvider.java revision 135c2e576f3dfea954ba628942c55adcb35a7cf6
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
18c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.content.ContentProvider;
19c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.content.ContentValues;
20c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.content.UriMatcher;
21c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.Cursor;
22c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.DatabaseUtils;
23c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.sqlite.SQLiteDatabase;
24c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.database.sqlite.SQLiteOpenHelper;
25135c2e576f3dfea954ba628942c55adcb35a7cf6George Mountimport android.database.sqlite.SQLiteQueryBuilder;
26c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.net.Uri;
27c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.os.CancellationSignal;
28c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport android.provider.BaseColumns;
29c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
30135c2e576f3dfea954ba628942c55adcb35a7cf6George Mountimport com.google.android.gms.common.util.VisibleForTesting;
31135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
32c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport java.util.ArrayList;
33c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountimport java.util.List;
34c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
35c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount/**
36c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * A provider that gives access to photo and video information for media stored
37c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * on the server. Only media that is or will be put on the server will be
38c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * accessed by this provider. Use Photos.CONTENT_URI to query all photos and
39c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * videos. Use Albums.CONTENT_URI to query all albums. Use Metadata.CONTENT_URI
40c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * to query metadata about a photo or video, based on the ID of the media. Use
41c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * ImageCache.THUMBNAIL_CONTENT_URI, ImageCache.PREVIEW_CONTENT_URI, or
42c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * ImageCache.ORIGINAL_CONTENT_URI to query the path of the thumbnail, preview,
43c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * or original-sized image respectfully. <br/>
44c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * To add or update metadata, use the update function rather than insert. All
45c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * values for the metadata must be in the ContentValues, even if they are also
46c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * in the selection. The selection and selectionArgs are not used when updating
47c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount * metadata. If the metadata values are null, the row will be deleted.
48c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount */
49c8419b4e5e3302f2efc7ea629891041a14219aa7George Mountpublic class PhotoProvider extends ContentProvider {
50c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @SuppressWarnings("unused")
51c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static final String TAG = PhotoProvider.class.getSimpleName();
52135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
53135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected static final String DB_NAME = "photo.db";
54135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public static final String AUTHORITY = PhotoProviderAuthority.AUTHORITY;
55c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    static final Uri BASE_CONTENT_URI = new Uri.Builder().scheme("content").authority(AUTHORITY)
56c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            .build();
57c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
58135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    // Used to allow mocking out the change notification because
59135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    // MockContextResolver disallows system-wide notification.
60135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public static interface ChangeNotification {
61135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        void notifyChange(Uri uri);
62135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    }
63135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
64c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
65c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns that can be accessed via PHOTOS_CONTENT_URI.
66c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
67c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface Photos extends BaseColumns {
68c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
69c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Internal database table used for basic photo information.
70c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
71c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String TABLE = "photo";
72c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
73c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Content URI for basic photo and video information.
74c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
75c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
76c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
77c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Identifier used on the server. Long value.
78c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
79c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String SERVER_ID = "server_id";
80c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
81c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the width of the original image. Integer value.
82c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
83c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String WIDTH = "width";
84c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
85c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the height of the original image. Integer value.
86c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
87c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String HEIGHT = "height";
88c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
89c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the date that the original image was taken. Long
90c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * value indicating the milliseconds since epoch in the GMT time zone.
91c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
92c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String DATE_TAKEN = "date_taken";
93c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
94c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name indicating the long value of the album id that this image
95c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * resides in. Will be NULL if it it has not been uploaded to the
96c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * server.
97c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
98c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String ALBUM_ID = "album_id";
99c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
100c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * The column name for the mime-type String.
101c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
102c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String MIME_TYPE = "mime_type";
103c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
104c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
105c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
106c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns and Uri for accessing album information.
107c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
108c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface Albums extends BaseColumns {
109c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
110c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Internal database table used album information.
111c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
112c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String TABLE = "album";
113c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
114c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Content URI for album information.
115c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
116c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
117c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
118c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Parent directory or null if this is in the root.
119c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
120c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String PARENT_ID = "parent";
121c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
122c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the name of the album. String value.
123c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
124c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String NAME = "name";
125c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
126c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the visibility level of the album. Can be any of the
127c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * VISIBILITY_* values.
128c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
129c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String VISIBILITY = "visibility";
130c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
131c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Column name for the server identifier for this album. NULL if the
132c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * server doesn't have this album yet.
133c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
134c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String SERVER_ID = "server_id";
135c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
136c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // Privacy values for Albums.VISIBILITY
137c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_PRIVATE = 1;
138c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_SHARED = 2;
139c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int VISIBILITY_PUBLIC = 3;
140c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
141c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
142c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
143c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns and Uri for accessing photo and video metadata
144c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
145c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface Metadata extends BaseColumns {
146c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
147c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Internal database table used metadata information.
148c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
149c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String TABLE = "metadata";
150c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
151c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Content URI for photo and video metadata.
152c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
153c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
154c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
155c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Foreign key to photo_id. Long value.
156c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
157c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String PHOTO_ID = "photo_id";
158c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
159c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Metadata key. String value
160c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
161c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String KEY = "key";
162c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
163c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Metadata value. Type is based on key.
164c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
165c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String VALUE = "value";
166c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
167c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
168c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
169c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * Contains columns and Uri for maintaining the image cache.
170c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
171c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public static interface ImageCache extends BaseColumns {
172c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
173c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Internal database table used for the image cache
174c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
175c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String TABLE = "image_cache";
176c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
177c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
178c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * The image_type query parameter required for accessing a specific
179c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * image
180c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
181c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String IMAGE_TYPE_QUERY_PARAMETER = "image_type";
182c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
183c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // ImageCache.IMAGE_TYPE values
184c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int IMAGE_TYPE_THUMBNAIL = 1;
185c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int IMAGE_TYPE_PREVIEW = 2;
186c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final int IMAGE_TYPE_ORIGINAL = 3;
187c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
188c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
189c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Content URI for retrieving image paths. The
190c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * IMAGE_TYPE_QUERY_PARAMETER must be used in queries.
191c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
192c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
193c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
194c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
195c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * Foreign key to the photos._id. Long value.
196c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
197135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        public static final String PHOTO_ID = "photo_id";
198c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
199c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * One of IMAGE_TYPE_* values.
200c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
201c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String IMAGE_TYPE = "image_type";
202c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        /**
203c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         * The String path to the image.
204c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount         */
205c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        public static final String PATH = "path";
206c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    };
207c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
208c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    // SQL used within this class.
209c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE_ID = BaseColumns._ID + " = ?";
210c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE_METADATA_ID = Metadata.PHOTO_ID + " = ? AND "
211c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Metadata.KEY + " = ?";
212c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
213c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_ALBUM_ID = "SELECT " + Albums._ID + " FROM "
214c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Albums.TABLE;
215c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_PHOTO_ID = "SELECT " + Photos._ID + " FROM "
216c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            + Photos.TABLE;
217c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_PHOTO_COUNT = "SELECT COUNT(*) FROM " + Photos.TABLE;
218c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String DELETE_PHOTOS = "DELETE FROM " + Photos.TABLE;
219c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String DELETE_METADATA = "DELETE FROM " + Metadata.TABLE;
220c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String SELECT_METADATA_COUNT = "SELECT COUNT(*) FROM " + Metadata.TABLE;
221c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String WHERE = " WHERE ";
222c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String IN = " IN ";
223c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String NESTED_SELECT_START = "(";
224c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final String NESTED_SELECT_END = ")";
225c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
226c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    /**
227c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     * For selecting the mime-type for an image.
228c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount     */
229c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static final String[] PROJECTION_MIME_TYPE = {
230c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        Photos.MIME_TYPE,
231c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    };
232c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
233135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    private static final String[] BASE_COLUMNS_ID = {
234135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        BaseColumns._ID,
235135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    };
236135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
237135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected ChangeNotification mNotifier = null;
238c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private SQLiteOpenHelper mOpenHelper;
239c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
240c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
241c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_PHOTO = 1;
242c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_PHOTO_ID = 2;
243c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_ALBUM = 3;
244c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_ALBUM_ID = 4;
245c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_METADATA = 5;
246c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_METADATA_ID = 6;
247c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static final int MATCH_IMAGE = 7;
248c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
249c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    static {
250c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Photos.TABLE, MATCH_PHOTO);
251c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against Photos._ID
252c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Photos.TABLE + "/#", MATCH_PHOTO_ID);
253c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Albums.TABLE, MATCH_ALBUM);
254c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against Albums._ID
255c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Albums.TABLE + "/#", MATCH_ALBUM_ID);
256c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Metadata.TABLE, MATCH_METADATA);
257c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against metadata/<Metadata._ID>
258c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, Metadata.TABLE + "/#", MATCH_METADATA_ID);
259c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // match against image_cache/<ImageCache.PHOTO_ID>
260c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        sUriMatcher.addURI(AUTHORITY, ImageCache.TABLE + "/#", MATCH_IMAGE);
261c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
262c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
263c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
264c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public int delete(Uri uri, String selection, String[] selectionArgs) {
265c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
266c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (match == MATCH_IMAGE) {
267c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            throw new IllegalArgumentException("Cannot delete from image cache");
268c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
269c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selection = addIdToSelection(match, selection);
270c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
271c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        List<Uri> changeUris = new ArrayList<Uri>();
272c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int deleted = 0;
273c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
274c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        db.beginTransaction();
275c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        try {
276c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            deleted = deleteCascade(db, match, selection, selectionArgs, changeUris, uri);
277c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            db.setTransactionSuccessful();
278c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        } finally {
279c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            db.endTransaction();
280c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
281c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        for (Uri changeUri : changeUris) {
282c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            notifyChanges(changeUri);
283c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
284c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return deleted;
285c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
286c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
287c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
288c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public String getType(Uri uri) {
289c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        Cursor cursor = query(uri, PROJECTION_MIME_TYPE, null, null, null);
290c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String mimeType = null;
291c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (cursor.moveToNext()) {
292c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            mimeType = cursor.getString(0);
293c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
294c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        cursor.close();
295c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return mimeType;
296c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
297c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
298c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
299c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public Uri insert(Uri uri, ContentValues values) {
300c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        // Cannot insert into this ContentProvider
301c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return null;
302c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
303c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
304c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
305c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public boolean onCreate() {
306c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        mOpenHelper = createDatabaseHelper();
307c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return true;
308c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
309c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
310c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
311135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public void shutdown() {
312135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        getDatabaseHelper().close();
313135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    }
314135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
315135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    @Override
316c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
317c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String sortOrder) {
318c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return query(uri, projection, selection, selectionArgs, sortOrder, null);
319c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
320c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
321c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
322c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
323c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String sortOrder, CancellationSignal cancellationSignal) {
324c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
325c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selection = addIdToSelection(match, selection);
326c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
327c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table = getTableFromMatch(match, uri);
328c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
329c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return db.query(false, table, projection, selection, selectionArgs, null, null, sortOrder,
330c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                null, cancellationSignal);
331c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
332c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
333c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    @Override
334c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
335c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = matchUri(uri);
336c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int rowsUpdated = 0;
337c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
338c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        db.beginTransaction();
339c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        try {
340c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            if (match == MATCH_METADATA) {
341c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                rowsUpdated = modifyMetadata(db, values);
342c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            } else {
343c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                selection = addIdToSelection(match, selection);
344c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs);
345c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                String table = getTableFromMatch(match, uri);
346c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                rowsUpdated = db.update(table, values, selection, selectionArgs);
347c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            }
348c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            db.setTransactionSuccessful();
349c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        } finally {
350c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            db.endTransaction();
351c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
352c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        notifyChanges(uri);
353c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return rowsUpdated;
354c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
355c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
356135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    @VisibleForTesting
357135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    public void setMockNotification(ChangeNotification notification) {
358135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        mNotifier = notification;
359135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    }
360135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount
361c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String addIdToSelection(int match, String selection) {
362c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String where;
363c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
364c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
365c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
366c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
367c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                where = WHERE_ID;
368c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
369c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
370c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                return selection;
371c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
372c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.concatenateWhere(selection, where);
373c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
374c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
375c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String[] addIdToSelectionArgs(int match, Uri uri, String[] selectionArgs) {
376c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String[] whereArgs;
377c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
378c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
379c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
380c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
381c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                whereArgs = new String[] {
382c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                    uri.getPathSegments().get(1),
383c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                };
384c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
385c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
386c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                return selectionArgs;
387c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
388c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.appendSelectionArgs(selectionArgs, whereArgs);
389c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
390c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
391c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String[] addMetadataKeysToSelectionArgs(String[] selectionArgs, Uri uri) {
392c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        List<String> segments = uri.getPathSegments();
393c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String[] additionalArgs = {
394c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                segments.get(1),
395c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                segments.get(2),
396c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        };
397c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
398c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return DatabaseUtils.appendSelectionArgs(selectionArgs, additionalArgs);
399c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
400c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
401c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static String getTableFromMatch(int match, Uri uri) {
402c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table;
403c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
404c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO:
405c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID:
406c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Photos.TABLE;
407c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
408c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM:
409c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID:
410c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Albums.TABLE;
411c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
412c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA:
413c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_METADATA_ID:
414c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                table = Metadata.TABLE;
415c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
416c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            default:
417c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                throw unknownUri(uri);
418c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
419c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return table;
420c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
421c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
422c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected final SQLiteOpenHelper getDatabaseHelper() {
423c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return mOpenHelper;
424c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
425c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
426c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected SQLiteOpenHelper createDatabaseHelper() {
427135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        return new PhotoDatabase(getContext(), DB_NAME);
428c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
429c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
430c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private int modifyMetadata(SQLiteDatabase db, ContentValues values) {
431c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String[] selectionArgs = {
432c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            values.getAsString(Metadata.PHOTO_ID),
433c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            values.getAsString(Metadata.KEY),
434c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        };
435c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int rowCount;
436c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (values.get(Metadata.VALUE) == null) {
437c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            rowCount = db.delete(Metadata.TABLE, WHERE_METADATA_ID, selectionArgs);
438c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        } else {
439c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            rowCount = (int) DatabaseUtils.queryNumEntries(db, Metadata.TABLE, WHERE_METADATA_ID,
440c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                    selectionArgs);
441c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            if (rowCount > 0) {
442c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                db.update(Metadata.TABLE, values, WHERE_METADATA_ID, selectionArgs);
443c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            } else {
444c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                db.insert(Metadata.TABLE, null, values);
445c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                rowCount = 1;
446c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            }
447c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
448c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return rowCount;
449c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
450c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
451c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private int matchUri(Uri uri) {
452c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        int match = sUriMatcher.match(uri);
453c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (match == UriMatcher.NO_MATCH) {
454c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            throw unknownUri(uri);
455c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
456c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return match;
457c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
458c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
459c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected void notifyChanges(Uri uri) {
460135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        if (mNotifier != null) {
461135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount            mNotifier.notifyChange(uri);
462135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        } else {
463135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount            getContext().getContentResolver().notifyChange(uri, null, false);
464135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        }
465c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
466c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
467c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static IllegalArgumentException unknownUri(Uri uri) {
468c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        return new IllegalArgumentException("Unknown Uri format: " + uri);
469c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
470c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
471135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount    protected static String nestWhere(String matchColumn, String table, String nestedWhere) {
472135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        String query = SQLiteQueryBuilder.buildQueryString(false, table, BASE_COLUMNS_ID,
473135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount                nestedWhere, null, null, null, null);
474135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        return matchColumn + IN + NESTED_SELECT_START + query + NESTED_SELECT_END;
475c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
476c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
477c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    protected static int deleteCascade(SQLiteDatabase db, int match, String selection,
478c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String[] selectionArgs, List<Uri> changeUris, Uri uri) {
479c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        switch (match) {
480c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO:
481c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_PHOTO_ID: {
482135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount                deleteCascadeMetadata(db, selection, selectionArgs, changeUris);
483c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
484c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            }
485c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM:
486c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            case MATCH_ALBUM_ID: {
487135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount                deleteCascadePhotos(db, selection, selectionArgs, changeUris);
488c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount                break;
489c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            }
490c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
491c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        String table = getTableFromMatch(match, uri);
492135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        int deleted = db.delete(table, selection, selectionArgs);
493135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        if (deleted > 0) {
494135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount            changeUris.add(uri);
495c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
496135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        return deleted;
497c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
498c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
499c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static void deleteCascadePhotos(SQLiteDatabase db, String albumSelect,
500c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String[] selectArgs, List<Uri> changeUris) {
501135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        String photoWhere = nestWhere(Photos.ALBUM_ID, Albums.TABLE, albumSelect);
502135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        deleteCascadeMetadata(db, photoWhere, selectArgs, changeUris);
503135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        int deleted = db.delete(Photos.TABLE, photoWhere, selectArgs);
504c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (deleted > 0) {
505c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            changeUris.add(Photos.CONTENT_URI);
506c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
507c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
508c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount
509c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    private static void deleteCascadeMetadata(SQLiteDatabase db, String photosSelect,
510c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            String[] selectArgs, List<Uri> changeUris) {
511135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        String metadataWhere = nestWhere(Metadata.PHOTO_ID, Photos.TABLE, photosSelect);
512135c2e576f3dfea954ba628942c55adcb35a7cf6George Mount        int deleted = db.delete(Metadata.TABLE, metadataWhere, selectArgs);
513c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        if (deleted > 0) {
514c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount            changeUris.add(Metadata.CONTENT_URI);
515c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount        }
516c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount    }
517c8419b4e5e3302f2efc7ea629891041a14219aa7George Mount}
518