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