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 class LocalUriMatcher { 23 24 // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 25 // are stored in the "files" table, so do not renumber them unless you also add 26 // a corresponding database upgrade step for it. 27 static final int IMAGES_MEDIA = 1; 28 static final int IMAGES_MEDIA_ID = 2; 29 static final int IMAGES_MEDIA_ID_THUMBNAIL = 3; 30 static final int IMAGES_THUMBNAILS = 4; 31 static final int IMAGES_THUMBNAILS_ID = 5; 32 33 static final int AUDIO_MEDIA = 100; 34 static final int AUDIO_MEDIA_ID = 101; 35 static final int AUDIO_MEDIA_ID_GENRES = 102; 36 static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 37 static final int AUDIO_GENRES = 106; 38 static final int AUDIO_GENRES_ID = 107; 39 static final int AUDIO_GENRES_ID_MEMBERS = 108; 40 static final int AUDIO_GENRES_ALL_MEMBERS = 109; 41 static final int AUDIO_PLAYLISTS = 110; 42 static final int AUDIO_PLAYLISTS_ID = 111; 43 static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 44 static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 45 static final int AUDIO_ARTISTS = 114; 46 static final int AUDIO_ARTISTS_ID = 115; 47 static final int AUDIO_ALBUMS = 116; 48 static final int AUDIO_ALBUMS_ID = 117; 49 static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 50 static final int AUDIO_ALBUMART = 119; 51 static final int AUDIO_ALBUMART_ID = 120; 52 static final int AUDIO_ALBUMART_FILE_ID = 121; 53 54 static final int VIDEO_MEDIA = 200; 55 static final int VIDEO_MEDIA_ID = 201; 56 static final int VIDEO_MEDIA_ID_THUMBNAIL = 202; 57 static final int VIDEO_THUMBNAILS = 203; 58 static final int VIDEO_THUMBNAILS_ID = 204; 59 60 static final int VOLUMES = 300; 61 static final int VOLUMES_ID = 301; 62 63 static final int MEDIA_SCANNER = 500; 64 65 static final int FS_ID = 600; 66 static final int VERSION = 601; 67 68 static final int FILES = 700; 69 static final int FILES_ID = 701; 70 71 static final int DOWNLOADS = 800; 72 static final int DOWNLOADS_ID = 801; 73 74 static final int PICKER = 900; 75 static final int PICKER_ID = 901; 76 static final int PICKER_INTERNAL_MEDIA_ALL = 902; 77 static final int PICKER_INTERNAL_MEDIA_LOCAL = 903; 78 static final int PICKER_INTERNAL_ALBUMS_ALL = 904; 79 static final int PICKER_INTERNAL_ALBUMS_LOCAL = 905; 80 81 // MediaProvider Command Line Interface 82 static final int CLI = 100_000; 83 84 private final UriMatcher mPublic = new UriMatcher(UriMatcher.NO_MATCH); 85 private final UriMatcher mHidden = new UriMatcher(UriMatcher.NO_MATCH); 86 matchUri(Uri uri, boolean allowHidden)87 int matchUri(Uri uri, boolean allowHidden) { 88 final int publicMatch = mPublic.match(uri); 89 if (publicMatch != UriMatcher.NO_MATCH) { 90 return publicMatch; 91 } 92 93 final int hiddenMatch = mHidden.match(uri); 94 if (hiddenMatch != UriMatcher.NO_MATCH) { 95 // Detect callers asking about hidden behavior by looking closer when 96 // the matchers diverge; we only care about apps that are explicitly 97 // targeting a specific public API level. 98 if (!allowHidden) { 99 throw new IllegalStateException("Unknown URL: " + uri + " is hidden API"); 100 } 101 return hiddenMatch; 102 } 103 104 return UriMatcher.NO_MATCH; 105 } 106 LocalUriMatcher(String auth)107 LocalUriMatcher(String auth) { 108 // Warning: Do not move these exact string matches below "*/.." matches. 109 // If "*/.." match is added to mPublic children before "picker/#/#", then while matching 110 // "picker/0/10", UriMatcher matches "*" node with "picker" and tries to match "0/10" 111 // with children of "*". 112 // UriMatcher does not look for exact "picker" string match if it finds * node before 113 // it. It finds the first best child match and proceeds the match from there without 114 // looking at other siblings. 115 mPublic.addURI(auth, "picker", PICKER); 116 // TODO(b/195009139): Remove after switching picker URI to new format 117 // content://media/picker/<user-id>/<media-id> 118 mPublic.addURI(auth, "picker/#/#", PICKER_ID); 119 // content://media/picker/<user-id>/<authority>/media/<media-id> 120 mPublic.addURI(auth, "picker/#/*/media/*", PICKER_ID); 121 122 mPublic.addURI(auth, "cli", CLI); 123 124 mPublic.addURI(auth, "*/images/media", IMAGES_MEDIA); 125 mPublic.addURI(auth, "*/images/media/#", IMAGES_MEDIA_ID); 126 mPublic.addURI(auth, "*/images/media/#/thumbnail", IMAGES_MEDIA_ID_THUMBNAIL); 127 mPublic.addURI(auth, "*/images/thumbnails", IMAGES_THUMBNAILS); 128 mPublic.addURI(auth, "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 129 130 mPublic.addURI(auth, "*/audio/media", AUDIO_MEDIA); 131 mPublic.addURI(auth, "*/audio/media/#", AUDIO_MEDIA_ID); 132 mPublic.addURI(auth, "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 133 mPublic.addURI(auth, "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 134 mPublic.addURI(auth, "*/audio/genres", AUDIO_GENRES); 135 mPublic.addURI(auth, "*/audio/genres/#", AUDIO_GENRES_ID); 136 mPublic.addURI(auth, "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 137 // TODO: not actually defined in API, but CTS tested 138 mPublic.addURI(auth, "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS); 139 mPublic.addURI(auth, "*/audio/playlists", AUDIO_PLAYLISTS); 140 mPublic.addURI(auth, "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 141 mPublic.addURI(auth, "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 142 mPublic.addURI(auth, "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 143 mPublic.addURI(auth, "*/audio/artists", AUDIO_ARTISTS); 144 mPublic.addURI(auth, "*/audio/artists/#", AUDIO_ARTISTS_ID); 145 mPublic.addURI(auth, "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 146 mPublic.addURI(auth, "*/audio/albums", AUDIO_ALBUMS); 147 mPublic.addURI(auth, "*/audio/albums/#", AUDIO_ALBUMS_ID); 148 // TODO: not actually defined in API, but CTS tested 149 mPublic.addURI(auth, "*/audio/albumart", AUDIO_ALBUMART); 150 // TODO: not actually defined in API, but CTS tested 151 mPublic.addURI(auth, "*/audio/albumart/#", AUDIO_ALBUMART_ID); 152 // TODO: not actually defined in API, but CTS tested 153 mPublic.addURI(auth, "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 154 155 mPublic.addURI(auth, "*/video/media", VIDEO_MEDIA); 156 mPublic.addURI(auth, "*/video/media/#", VIDEO_MEDIA_ID); 157 mPublic.addURI(auth, "*/video/media/#/thumbnail", VIDEO_MEDIA_ID_THUMBNAIL); 158 mPublic.addURI(auth, "*/video/thumbnails", VIDEO_THUMBNAILS); 159 mPublic.addURI(auth, "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 160 161 mPublic.addURI(auth, "*/media_scanner", MEDIA_SCANNER); 162 163 // NOTE: technically hidden, since Uri is never exposed 164 mPublic.addURI(auth, "*/fs_id", FS_ID); 165 // NOTE: technically hidden, since Uri is never exposed 166 mPublic.addURI(auth, "*/version", VERSION); 167 168 mHidden.addURI(auth, "picker_internal/media/all", PICKER_INTERNAL_MEDIA_ALL); 169 mHidden.addURI(auth, "picker_internal/media/local", PICKER_INTERNAL_MEDIA_LOCAL); 170 mHidden.addURI(auth, "picker_internal/albums/all", PICKER_INTERNAL_ALBUMS_ALL); 171 mHidden.addURI(auth, "picker_internal/albums/local", PICKER_INTERNAL_ALBUMS_LOCAL); 172 mHidden.addURI(auth, "*", VOLUMES_ID); 173 mHidden.addURI(auth, null, VOLUMES); 174 175 mPublic.addURI(auth, "*/file", FILES); 176 mPublic.addURI(auth, "*/file/#", FILES_ID); 177 178 mPublic.addURI(auth, "*/downloads", DOWNLOADS); 179 mPublic.addURI(auth, "*/downloads/#", DOWNLOADS_ID); 180 } 181 } 182