blob: 1c26fd917f76588c0e2a44f5ed1c02b0eece7105 [file] [log] [blame]
Ivan Chianga972d042018-10-15 15:23:02 +08001/*
2 * Copyright (C) 2018 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
17package android.content;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21
22import java.util.ArrayList;
23
24/**
25 * Provides utility methods for matching MIME type filters used in ContentProvider.
26 *
27 * <p>Wildcards are allowed only instead of the entire type or subtype with a tree prefix.
28 * Eg. image\/*, *\/* is a valid filter and will match image/jpeg, but image/j* is invalid and
29 * it will not match image/jpeg. Suffixes and parameters are not supported, and they are treated
30 * as part of the subtype during matching. Neither type nor subtype can be empty.
31 *
32 * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike the formal
33 * RFC definitions. As a result, you should always write these elements with lower case letters,
34 * or use {@link android.content.Intent#normalizeMimeType} to ensure that they are converted to
35 * lower case.</em>
36 *
37 * <p>MIME types can be null or ill-formatted. In such case they won't match anything.
38 *
39 * <p>MIME type filters must be correctly formatted, or an exception will be thrown.
40 * Copied from support library.
41 * {@hide}
42 */
43public final class MimeTypeFilter {
44
45 private MimeTypeFilter() {
46 }
47
48 private static boolean mimeTypeAgainstFilter(
49 @NonNull String[] mimeTypeParts, @NonNull String[] filterParts) {
50 if (filterParts.length != 2) {
51 throw new IllegalArgumentException(
52 "Ill-formatted MIME type filter. Must be type/subtype.");
53 }
54 if (filterParts[0].isEmpty() || filterParts[1].isEmpty()) {
55 throw new IllegalArgumentException(
56 "Ill-formatted MIME type filter. Type or subtype empty.");
57 }
58 if (mimeTypeParts.length != 2) {
59 return false;
60 }
61 if (!"*".equals(filterParts[0])
62 && !filterParts[0].equals(mimeTypeParts[0])) {
63 return false;
64 }
65 if (!"*".equals(filterParts[1])
66 && !filterParts[1].equals(mimeTypeParts[1])) {
67 return false;
68 }
69
70 return true;
71 }
72
73 /**
74 * Matches one nullable MIME type against one MIME type filter.
75 * @return True if the {@code mimeType} matches the {@code filter}.
76 */
77 public static boolean matches(@Nullable String mimeType, @NonNull String filter) {
78 if (mimeType == null) {
79 return false;
80 }
81
82 final String[] mimeTypeParts = mimeType.split("/");
83 final String[] filterParts = filter.split("/");
84
85 return mimeTypeAgainstFilter(mimeTypeParts, filterParts);
86 }
87
88 /**
89 * Matches one nullable MIME type against an array of MIME type filters.
90 * @return The first matching filter, or null if nothing matches.
91 */
92 @Nullable
93 public static String matches(
94 @Nullable String mimeType, @NonNull String[] filters) {
95 if (mimeType == null) {
96 return null;
97 }
98
99 final String[] mimeTypeParts = mimeType.split("/");
100 for (String filter : filters) {
101 final String[] filterParts = filter.split("/");
102 if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
103 return filter;
104 }
105 }
106
107 return null;
108 }
109
110 /**
111 * Matches multiple MIME types against an array of MIME type filters.
112 * @return The first matching MIME type, or null if nothing matches.
113 */
114 @Nullable
115 public static String matches(
116 @Nullable String[] mimeTypes, @NonNull String filter) {
117 if (mimeTypes == null) {
118 return null;
119 }
120
121 final String[] filterParts = filter.split("/");
122 for (String mimeType : mimeTypes) {
123 final String[] mimeTypeParts = mimeType.split("/");
124 if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
125 return mimeType;
126 }
127 }
128
129 return null;
130 }
131
132 /**
133 * Matches multiple MIME types against an array of MIME type filters.
134 * @return The list of matching MIME types, or empty array if nothing matches.
135 */
136 @NonNull
137 public static String[] matchesMany(
138 @Nullable String[] mimeTypes, @NonNull String filter) {
139 if (mimeTypes == null) {
140 return new String[] {};
141 }
142
143 final ArrayList<String> list = new ArrayList<>();
144 final String[] filterParts = filter.split("/");
145 for (String mimeType : mimeTypes) {
146 final String[] mimeTypeParts = mimeType.split("/");
147 if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) {
148 list.add(mimeType);
149 }
150 }
151
152 return list.toArray(new String[list.size()]);
153 }
154}