• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.media;
18 
19 import android.content.UriMatcher;
20 import android.net.Uri;
21 
22 import com.android.providers.media.photopicker.v2.PickerUriResolverV2;
23 
24 class LocalUriMatcher {
25 
26     // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS
27     // are stored in the "files" table, so do not renumber them unless you also add
28     // a corresponding database upgrade step for it.
29     static final int IMAGES_MEDIA = 1;
30     static final int IMAGES_MEDIA_ID = 2;
31     static final int IMAGES_MEDIA_ID_THUMBNAIL = 3;
32     static final int IMAGES_THUMBNAILS = 4;
33     static final int IMAGES_THUMBNAILS_ID = 5;
34 
35     static final int AUDIO_MEDIA = 100;
36     static final int AUDIO_MEDIA_ID = 101;
37     static final int AUDIO_MEDIA_ID_GENRES = 102;
38     static final int AUDIO_MEDIA_ID_GENRES_ID = 103;
39     static final int AUDIO_GENRES = 106;
40     static final int AUDIO_GENRES_ID = 107;
41     static final int AUDIO_GENRES_ID_MEMBERS = 108;
42     static final int AUDIO_GENRES_ALL_MEMBERS = 109;
43     static final int AUDIO_PLAYLISTS = 110;
44     static final int AUDIO_PLAYLISTS_ID = 111;
45     static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112;
46     static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113;
47     static final int AUDIO_ARTISTS = 114;
48     static final int AUDIO_ARTISTS_ID = 115;
49     static final int AUDIO_ALBUMS = 116;
50     static final int AUDIO_ALBUMS_ID = 117;
51     static final int AUDIO_ARTISTS_ID_ALBUMS = 118;
52     static final int AUDIO_ALBUMART = 119;
53     static final int AUDIO_ALBUMART_ID = 120;
54     static final int AUDIO_ALBUMART_FILE_ID = 121;
55 
56     static final int VIDEO_MEDIA = 200;
57     static final int VIDEO_MEDIA_ID = 201;
58     static final int VIDEO_MEDIA_ID_THUMBNAIL = 202;
59     static final int VIDEO_THUMBNAILS = 203;
60     static final int VIDEO_THUMBNAILS_ID = 204;
61 
62     static final int VOLUMES = 300;
63     static final int VOLUMES_ID = 301;
64 
65     static final int MEDIA_SCANNER = 500;
66 
67     static final int FS_ID = 600;
68     static final int VERSION = 601;
69 
70     static final int FILES = 700;
71     static final int FILES_ID = 701;
72 
73     static final int DOWNLOADS = 800;
74     static final int DOWNLOADS_ID = 801;
75 
76     static final int PICKER = 900;
77     public static final int PICKER_ID = 901;
78     static final int PICKER_INTERNAL_MEDIA_ALL = 902;
79     static final int PICKER_INTERNAL_MEDIA_LOCAL = 903;
80     static final int PICKER_INTERNAL_ALBUMS_ALL = 904;
81     static final int PICKER_INTERNAL_ALBUMS_LOCAL = 905;
82     public static final int PICKER_GET_CONTENT_ID = 906;
83     public static final int PICKER_TRANSCODED_ID = 907;
84 
85     /**
86      * Picker V2 base URI. {@see PickerUriResolverV2}.
87      */
88     public static final int PICKER_INTERNAL_V2 = 908;
89 
90     public static final int MEDIA_GRANTS = 1000;
91 
92     // MediaProvider Command Line Interface
93     static final int CLI = 100_000;
94 
95     private final UriMatcher mPublic = new UriMatcher(UriMatcher.NO_MATCH);
96     private final UriMatcher mHidden = new UriMatcher(UriMatcher.NO_MATCH);
97 
98     /* Matcher for Picker V2 URI */
99     private final UriMatcher mPickerInternalV2 = new UriMatcher(UriMatcher.NO_MATCH);
100 
matchUri(Uri uri, boolean allowHidden)101     int matchUri(Uri uri, boolean allowHidden) {
102         return matchUri(uri, allowHidden, /* isCallerPhotoPicker */ false);
103     }
104 
matchUri(Uri uri, boolean allowHidden, boolean isCallerPhotoPicker)105     int matchUri(Uri uri, boolean allowHidden, boolean isCallerPhotoPicker) {
106         final int publicMatch = mPublic.match(uri);
107         if (publicMatch != UriMatcher.NO_MATCH) {
108             return publicMatch;
109         }
110 
111         if (isCallerPhotoPicker) {
112             final int pickerInternalMatch = mPickerInternalV2.match(uri);
113             if (pickerInternalMatch != UriMatcher.NO_MATCH) {
114                 return pickerInternalMatch;
115             }
116         }
117 
118         final int hiddenMatch = mHidden.match(uri);
119         if (hiddenMatch != UriMatcher.NO_MATCH) {
120             // Detect callers asking about hidden behavior by looking closer when
121             // the matchers diverge; we only care about apps that are explicitly
122             // targeting a specific public API level.
123             if (!allowHidden) {
124                 throw new IllegalStateException("Unknown URL: " + uri + " is hidden API");
125             }
126             return hiddenMatch;
127         }
128 
129         return UriMatcher.NO_MATCH;
130     }
131 
LocalUriMatcher(String auth)132     LocalUriMatcher(String auth) {
133         // Warning: Do not move these exact string matches below "*/.." matches.
134         // If "*/.." match is added to mPublic children before "picker/#/#", then while matching
135         // "picker/0/10", UriMatcher matches "*" node with "picker" and tries to match "0/10"
136         // with children of "*".
137         // UriMatcher does not look for exact "picker" string match if it finds * node before
138         // it. It finds the first best child match and proceeds the match from there without
139         // looking at other siblings.
140         mPublic.addURI(auth, "picker", PICKER);
141         // TODO(b/195009139): Remove after switching picker URI to new format
142         // content://media/picker/<user-id>/<media-id>
143         mPublic.addURI(auth, "picker/#/#", PICKER_ID);
144         // content://media/picker/<user-id>/<authority>/media/<media-id>
145         mPublic.addURI(auth, "picker/#/*/media/*", PICKER_ID);
146 
147         // content://media/picker_get_content/<user-id>/<media-id>
148         mPublic.addURI(auth, "picker_get_content/#/#", PICKER_GET_CONTENT_ID);
149         // content://media/picker_get_content/<user-id>/<authority>/media/<media-id>
150         mPublic.addURI(auth, "picker_get_content/#/*/media/*", PICKER_GET_CONTENT_ID);
151 
152         // content://media/picker_transcoded/<user-id>/<authority>/media/<media-id>
153         mPublic.addURI(auth, "picker_transcoded/#/*/media/*", PICKER_TRANSCODED_ID);
154 
155         mPublic.addURI(auth, "cli", CLI);
156 
157         mPublic.addURI(auth, "*/images/media", IMAGES_MEDIA);
158         mPublic.addURI(auth, "*/images/media/#", IMAGES_MEDIA_ID);
159         mPublic.addURI(auth, "*/images/media/#/thumbnail", IMAGES_MEDIA_ID_THUMBNAIL);
160         mPublic.addURI(auth, "*/images/thumbnails", IMAGES_THUMBNAILS);
161         mPublic.addURI(auth, "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID);
162 
163         mPublic.addURI(auth, "*/audio/media", AUDIO_MEDIA);
164         mPublic.addURI(auth, "*/audio/media/#", AUDIO_MEDIA_ID);
165         mPublic.addURI(auth, "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES);
166         mPublic.addURI(auth, "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID);
167         mPublic.addURI(auth, "*/audio/genres", AUDIO_GENRES);
168         mPublic.addURI(auth, "*/audio/genres/#", AUDIO_GENRES_ID);
169         mPublic.addURI(auth, "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS);
170         // TODO: not actually defined in API, but CTS tested
171         mPublic.addURI(auth, "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS);
172         mPublic.addURI(auth, "*/audio/playlists", AUDIO_PLAYLISTS);
173         mPublic.addURI(auth, "*/audio/playlists/#", AUDIO_PLAYLISTS_ID);
174         mPublic.addURI(auth, "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS);
175         mPublic.addURI(auth, "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID);
176         mPublic.addURI(auth, "*/audio/artists", AUDIO_ARTISTS);
177         mPublic.addURI(auth, "*/audio/artists/#", AUDIO_ARTISTS_ID);
178         mPublic.addURI(auth, "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS);
179         mPublic.addURI(auth, "*/audio/albums", AUDIO_ALBUMS);
180         mPublic.addURI(auth, "*/audio/albums/#", AUDIO_ALBUMS_ID);
181         // TODO: not actually defined in API, but CTS tested
182         mPublic.addURI(auth, "*/audio/albumart", AUDIO_ALBUMART);
183         // TODO: not actually defined in API, but CTS tested
184         mPublic.addURI(auth, "*/audio/albumart/#", AUDIO_ALBUMART_ID);
185         // TODO: not actually defined in API, but CTS tested
186         mPublic.addURI(auth, "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID);
187 
188         mPublic.addURI(auth, "*/video/media", VIDEO_MEDIA);
189         mPublic.addURI(auth, "*/video/media/#", VIDEO_MEDIA_ID);
190         mPublic.addURI(auth, "*/video/media/#/thumbnail", VIDEO_MEDIA_ID_THUMBNAIL);
191         mPublic.addURI(auth, "*/video/thumbnails", VIDEO_THUMBNAILS);
192         mPublic.addURI(auth, "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID);
193 
194         mPublic.addURI(auth, "*/media_scanner", MEDIA_SCANNER);
195 
196         // NOTE: technically hidden, since Uri is never exposed
197         mPublic.addURI(auth, "*/fs_id", FS_ID);
198         // NOTE: technically hidden, since Uri is never exposed
199         mPublic.addURI(auth, "*/version", VERSION);
200 
201         mHidden.addURI(auth, "picker_internal/media/all", PICKER_INTERNAL_MEDIA_ALL);
202         mHidden.addURI(auth, "picker_internal/media/local", PICKER_INTERNAL_MEDIA_LOCAL);
203         mHidden.addURI(auth, "picker_internal/albums/all", PICKER_INTERNAL_ALBUMS_ALL);
204         mHidden.addURI(auth, "picker_internal/albums/local", PICKER_INTERNAL_ALBUMS_LOCAL);
205 
206         mPickerInternalV2.addURI(
207                 auth, PickerUriResolverV2.BASE_PICKER_PATH + "*", PICKER_INTERNAL_V2);
208         mPickerInternalV2.addURI(
209                 auth, PickerUriResolverV2.BASE_PICKER_PATH + "*/*", PICKER_INTERNAL_V2);
210 
211         mHidden.addURI(auth, "media_grants", MEDIA_GRANTS);
212         mHidden.addURI(auth, "*", VOLUMES_ID);
213         mHidden.addURI(auth, null, VOLUMES);
214 
215         mPublic.addURI(auth, "*/file", FILES);
216         mPublic.addURI(auth, "*/file/#", FILES_ID);
217 
218         mPublic.addURI(auth, "*/downloads", DOWNLOADS);
219         mPublic.addURI(auth, "*/downloads/#", DOWNLOADS_ID);
220     }
221 }
222