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 84 /** 85 * Picker V2 base URI. {@see PickerUriResolverV2}. 86 */ 87 public static final int PICKER_INTERNAL_V2 = 908; 88 89 public static final int MEDIA_GRANTS = 1000; 90 91 // MediaProvider Command Line Interface 92 static final int CLI = 100_000; 93 94 private final UriMatcher mPublic = new UriMatcher(UriMatcher.NO_MATCH); 95 private final UriMatcher mHidden = new UriMatcher(UriMatcher.NO_MATCH); 96 97 /* Matcher for Picker V2 URI */ 98 private final UriMatcher mPickerInternalV2 = new UriMatcher(UriMatcher.NO_MATCH); 99 matchUri(Uri uri, boolean allowHidden)100 int matchUri(Uri uri, boolean allowHidden) { 101 return matchUri(uri, allowHidden, /* isCallerPhotoPicker */ false); 102 } 103 matchUri(Uri uri, boolean allowHidden, boolean isCallerPhotoPicker)104 int matchUri(Uri uri, boolean allowHidden, boolean isCallerPhotoPicker) { 105 final int publicMatch = mPublic.match(uri); 106 if (publicMatch != UriMatcher.NO_MATCH) { 107 return publicMatch; 108 } 109 110 if (isCallerPhotoPicker) { 111 final int pickerInternalMatch = mPickerInternalV2.match(uri); 112 if (pickerInternalMatch != UriMatcher.NO_MATCH) { 113 return pickerInternalMatch; 114 } 115 } 116 117 final int hiddenMatch = mHidden.match(uri); 118 if (hiddenMatch != UriMatcher.NO_MATCH) { 119 // Detect callers asking about hidden behavior by looking closer when 120 // the matchers diverge; we only care about apps that are explicitly 121 // targeting a specific public API level. 122 if (!allowHidden) { 123 throw new IllegalStateException("Unknown URL: " + uri + " is hidden API"); 124 } 125 return hiddenMatch; 126 } 127 128 return UriMatcher.NO_MATCH; 129 } 130 LocalUriMatcher(String auth)131 LocalUriMatcher(String auth) { 132 // Warning: Do not move these exact string matches below "*/.." matches. 133 // If "*/.." match is added to mPublic children before "picker/#/#", then while matching 134 // "picker/0/10", UriMatcher matches "*" node with "picker" and tries to match "0/10" 135 // with children of "*". 136 // UriMatcher does not look for exact "picker" string match if it finds * node before 137 // it. It finds the first best child match and proceeds the match from there without 138 // looking at other siblings. 139 mPublic.addURI(auth, "picker", PICKER); 140 // TODO(b/195009139): Remove after switching picker URI to new format 141 // content://media/picker/<user-id>/<media-id> 142 mPublic.addURI(auth, "picker/#/#", PICKER_ID); 143 // content://media/picker/<user-id>/<authority>/media/<media-id> 144 mPublic.addURI(auth, "picker/#/*/media/*", PICKER_ID); 145 146 // content://media/picker_get_content/<user-id>/<media-id> 147 mPublic.addURI(auth, "picker_get_content/#/#", PICKER_GET_CONTENT_ID); 148 // content://media/picker_get_content/<user-id>/<authority>/media/<media-id> 149 mPublic.addURI(auth, "picker_get_content/#/*/media/*", PICKER_GET_CONTENT_ID); 150 151 mPublic.addURI(auth, "cli", CLI); 152 153 mPublic.addURI(auth, "*/images/media", IMAGES_MEDIA); 154 mPublic.addURI(auth, "*/images/media/#", IMAGES_MEDIA_ID); 155 mPublic.addURI(auth, "*/images/media/#/thumbnail", IMAGES_MEDIA_ID_THUMBNAIL); 156 mPublic.addURI(auth, "*/images/thumbnails", IMAGES_THUMBNAILS); 157 mPublic.addURI(auth, "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 158 159 mPublic.addURI(auth, "*/audio/media", AUDIO_MEDIA); 160 mPublic.addURI(auth, "*/audio/media/#", AUDIO_MEDIA_ID); 161 mPublic.addURI(auth, "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 162 mPublic.addURI(auth, "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 163 mPublic.addURI(auth, "*/audio/genres", AUDIO_GENRES); 164 mPublic.addURI(auth, "*/audio/genres/#", AUDIO_GENRES_ID); 165 mPublic.addURI(auth, "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 166 // TODO: not actually defined in API, but CTS tested 167 mPublic.addURI(auth, "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS); 168 mPublic.addURI(auth, "*/audio/playlists", AUDIO_PLAYLISTS); 169 mPublic.addURI(auth, "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 170 mPublic.addURI(auth, "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 171 mPublic.addURI(auth, "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 172 mPublic.addURI(auth, "*/audio/artists", AUDIO_ARTISTS); 173 mPublic.addURI(auth, "*/audio/artists/#", AUDIO_ARTISTS_ID); 174 mPublic.addURI(auth, "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 175 mPublic.addURI(auth, "*/audio/albums", AUDIO_ALBUMS); 176 mPublic.addURI(auth, "*/audio/albums/#", AUDIO_ALBUMS_ID); 177 // TODO: not actually defined in API, but CTS tested 178 mPublic.addURI(auth, "*/audio/albumart", AUDIO_ALBUMART); 179 // TODO: not actually defined in API, but CTS tested 180 mPublic.addURI(auth, "*/audio/albumart/#", AUDIO_ALBUMART_ID); 181 // TODO: not actually defined in API, but CTS tested 182 mPublic.addURI(auth, "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 183 184 mPublic.addURI(auth, "*/video/media", VIDEO_MEDIA); 185 mPublic.addURI(auth, "*/video/media/#", VIDEO_MEDIA_ID); 186 mPublic.addURI(auth, "*/video/media/#/thumbnail", VIDEO_MEDIA_ID_THUMBNAIL); 187 mPublic.addURI(auth, "*/video/thumbnails", VIDEO_THUMBNAILS); 188 mPublic.addURI(auth, "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 189 190 mPublic.addURI(auth, "*/media_scanner", MEDIA_SCANNER); 191 192 // NOTE: technically hidden, since Uri is never exposed 193 mPublic.addURI(auth, "*/fs_id", FS_ID); 194 // NOTE: technically hidden, since Uri is never exposed 195 mPublic.addURI(auth, "*/version", VERSION); 196 197 mHidden.addURI(auth, "picker_internal/media/all", PICKER_INTERNAL_MEDIA_ALL); 198 mHidden.addURI(auth, "picker_internal/media/local", PICKER_INTERNAL_MEDIA_LOCAL); 199 mHidden.addURI(auth, "picker_internal/albums/all", PICKER_INTERNAL_ALBUMS_ALL); 200 mHidden.addURI(auth, "picker_internal/albums/local", PICKER_INTERNAL_ALBUMS_LOCAL); 201 202 mPickerInternalV2.addURI( 203 auth, PickerUriResolverV2.BASE_PICKER_PATH + "*", PICKER_INTERNAL_V2); 204 mPickerInternalV2.addURI( 205 auth, PickerUriResolverV2.BASE_PICKER_PATH + "*/*", PICKER_INTERNAL_V2); 206 207 mHidden.addURI(auth, "media_grants", MEDIA_GRANTS); 208 mHidden.addURI(auth, "*", VOLUMES_ID); 209 mHidden.addURI(auth, null, VOLUMES); 210 211 mPublic.addURI(auth, "*/file", FILES); 212 mPublic.addURI(auth, "*/file/#", FILES_ID); 213 214 mPublic.addURI(auth, "*/downloads", DOWNLOADS); 215 mPublic.addURI(auth, "*/downloads/#", DOWNLOADS_ID); 216 } 217 } 218