blob: b78389bbe8da0ddacb5a4908e87729a961c9ba8c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 com.android.server;
18
Dianne Hackborn1d442e02009-04-20 18:14:05 -070019import java.io.PrintWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import java.util.ArrayList;
21import java.util.Collections;
22import java.util.Comparator;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Iterator;
26import java.util.List;
27import java.util.Map;
28import java.util.Set;
29
Jeff Brown2c376fc2011-01-28 17:34:01 -080030import android.net.Uri;
31import android.util.FastImmutableArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.util.Log;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070033import android.util.PrintWriterPrinter;
Joe Onorato8a9b2202010-02-26 18:56:32 -080034import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.util.LogPrinter;
36import android.util.Printer;
37
38import android.util.Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.Intent;
40import android.content.IntentFilter;
41
42/**
43 * {@hide}
44 */
45public class IntentResolver<F extends IntentFilter, R extends Object> {
46 final private static String TAG = "IntentResolver";
47 final private static boolean DEBUG = false;
48 final private static boolean localLOGV = DEBUG || Config.LOGV;
49
50 public void addFilter(F f) {
51 if (localLOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080052 Slog.v(TAG, "Adding filter: " + f);
53 f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
54 Slog.v(TAG, " Building Lookup Maps:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 }
56
57 mFilters.add(f);
58 int numS = register_intent_filter(f, f.schemesIterator(),
59 mSchemeToFilter, " Scheme: ");
60 int numT = register_mime_types(f, " Type: ");
61 if (numS == 0 && numT == 0) {
62 register_intent_filter(f, f.actionsIterator(),
63 mActionToFilter, " Action: ");
64 }
65 if (numT != 0) {
66 register_intent_filter(f, f.actionsIterator(),
67 mTypedActionToFilter, " TypedAction: ");
68 }
69 }
70
71 public void removeFilter(F f) {
72 removeFilterInternal(f);
73 mFilters.remove(f);
74 }
75
76 void removeFilterInternal(F f) {
77 if (localLOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080078 Slog.v(TAG, "Removing filter: " + f);
79 f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
80 Slog.v(TAG, " Cleaning Lookup Maps:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82
83 int numS = unregister_intent_filter(f, f.schemesIterator(),
84 mSchemeToFilter, " Scheme: ");
85 int numT = unregister_mime_types(f, " Type: ");
86 if (numS == 0 && numT == 0) {
87 unregister_intent_filter(f, f.actionsIterator(),
88 mActionToFilter, " Action: ");
89 }
90 if (numT != 0) {
91 unregister_intent_filter(f, f.actionsIterator(),
92 mTypedActionToFilter, " TypedAction: ");
93 }
94 }
95
Dianne Hackbornd4310ac2010-03-16 22:55:08 -070096 boolean dumpMap(PrintWriter out, String titlePrefix, String title,
Dianne Hackborncef65ee2010-09-30 18:27:22 -070097 String prefix, Map<String, ArrayList<F>> map, String packageName,
98 boolean printFilter) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 String eprefix = prefix + " ";
100 String fprefix = prefix + " ";
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700101 boolean printedSomething = false;
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700102 Printer printer = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 ArrayList<F> a = e.getValue();
105 final int N = a.size();
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700106 boolean printedHeader = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 for (int i=0; i<N; i++) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700108 F filter = a.get(i);
109 if (packageName != null && !packageName.equals(packageForFilter(filter))) {
110 continue;
111 }
112 if (title != null) {
113 out.print(titlePrefix); out.println(title);
114 title = null;
115 }
116 if (!printedHeader) {
117 out.print(eprefix); out.print(e.getKey()); out.println(":");
118 printedHeader = true;
119 }
120 printedSomething = true;
121 dumpFilter(out, fprefix, filter);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700122 if (printFilter) {
123 if (printer == null) {
124 printer = new PrintWriterPrinter(out);
125 }
126 filter.dump(printer, fprefix + " ");
127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 }
129 }
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700130 return printedSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 }
132
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700133 public boolean dump(PrintWriter out, String title, String prefix, String packageName,
134 boolean printFilter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700135 String innerPrefix = prefix + " ";
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700136 String sepPrefix = "\n" + prefix;
137 String curPrefix = title + "\n" + prefix;
138 if (dumpMap(out, curPrefix, "Full MIME Types:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700139 mTypeToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700140 curPrefix = sepPrefix;
141 }
142 if (dumpMap(out, curPrefix, "Base MIME Types:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700143 mBaseTypeToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700144 curPrefix = sepPrefix;
145 }
146 if (dumpMap(out, curPrefix, "Wild MIME Types:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700147 mWildTypeToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700148 curPrefix = sepPrefix;
149 }
150 if (dumpMap(out, curPrefix, "Schemes:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700151 mSchemeToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700152 curPrefix = sepPrefix;
153 }
154 if (dumpMap(out, curPrefix, "Non-Data Actions:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700155 mActionToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700156 curPrefix = sepPrefix;
157 }
158 if (dumpMap(out, curPrefix, "MIME Typed Actions:", innerPrefix,
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700159 mTypedActionToFilter, packageName, printFilter)) {
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700160 curPrefix = sepPrefix;
161 }
162 return curPrefix == sepPrefix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 }
164
165 private class IteratorWrapper implements Iterator<F> {
166 private final Iterator<F> mI;
167 private F mCur;
168
169 IteratorWrapper(Iterator<F> it) {
170 mI = it;
171 }
172
173 public boolean hasNext() {
174 return mI.hasNext();
175 }
176
177 public F next() {
178 return (mCur = mI.next());
179 }
180
181 public void remove() {
182 if (mCur != null) {
183 removeFilterInternal(mCur);
184 }
185 mI.remove();
186 }
187
188 }
189
190 /**
191 * Returns an iterator allowing filters to be removed.
192 */
193 public Iterator<F> filterIterator() {
194 return new IteratorWrapper(mFilters.iterator());
195 }
196
197 /**
198 * Returns a read-only set of the filters.
199 */
200 public Set<F> filterSet() {
201 return Collections.unmodifiableSet(mFilters);
202 }
203
Mihai Predaeae850c2009-05-13 10:13:48 +0200204 public List<R> queryIntentFromList(Intent intent, String resolvedType,
205 boolean defaultOnly, ArrayList<ArrayList<F>> listCut) {
206 ArrayList<R> resultList = new ArrayList<R>();
207
208 final boolean debug = localLOGV ||
209 ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
210
Jeff Brown2c376fc2011-01-28 17:34:01 -0800211 FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
Mihai Predaeae850c2009-05-13 10:13:48 +0200212 final String scheme = intent.getScheme();
213 int N = listCut.size();
214 for (int i = 0; i < N; ++i) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800215 buildResolveList(intent, categories, debug, defaultOnly,
Mihai Predaeae850c2009-05-13 10:13:48 +0200216 resolvedType, scheme, listCut.get(i), resultList);
217 }
218 sortResults(resultList);
219 return resultList;
220 }
221
Mihai Preda074edef2009-05-18 17:13:31 +0200222 public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 String scheme = intent.getScheme();
224
225 ArrayList<R> finalList = new ArrayList<R>();
226
227 final boolean debug = localLOGV ||
228 ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
229
Joe Onorato8a9b2202010-02-26 18:56:32 -0800230 if (debug) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 TAG, "Resolving type " + resolvedType + " scheme " + scheme
232 + " of intent " + intent);
233
234 ArrayList<F> firstTypeCut = null;
235 ArrayList<F> secondTypeCut = null;
236 ArrayList<F> thirdTypeCut = null;
237 ArrayList<F> schemeCut = null;
238
239 // If the intent includes a MIME type, then we want to collect all of
240 // the filters that match that MIME type.
241 if (resolvedType != null) {
242 int slashpos = resolvedType.indexOf('/');
243 if (slashpos > 0) {
244 final String baseType = resolvedType.substring(0, slashpos);
245 if (!baseType.equals("*")) {
246 if (resolvedType.length() != slashpos+2
247 || resolvedType.charAt(slashpos+1) != '*') {
248 // Not a wild card, so we can just look for all filters that
249 // completely match or wildcards whose base type matches.
250 firstTypeCut = mTypeToFilter.get(resolvedType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800251 if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 secondTypeCut = mWildTypeToFilter.get(baseType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800253 if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 } else {
255 // We can match anything with our base type.
256 firstTypeCut = mBaseTypeToFilter.get(baseType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800257 if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 secondTypeCut = mWildTypeToFilter.get(baseType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800259 if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 }
261 // Any */* types always apply, but we only need to do this
262 // if the intent type was not already */*.
263 thirdTypeCut = mWildTypeToFilter.get("*");
Joe Onorato8a9b2202010-02-26 18:56:32 -0800264 if (debug) Slog.v(TAG, "Third type cut: " + thirdTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 } else if (intent.getAction() != null) {
266 // The intent specified any type ({@literal *}/*). This
267 // can be a whole heck of a lot of things, so as a first
268 // cut let's use the action instead.
269 firstTypeCut = mTypedActionToFilter.get(intent.getAction());
Joe Onorato8a9b2202010-02-26 18:56:32 -0800270 if (debug) Slog.v(TAG, "Typed Action list: " + firstTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 }
272 }
273 }
274
275 // If the intent includes a data URI, then we want to collect all of
276 // the filters that match its scheme (we will further refine matches
277 // on the authority and path by directly matching each resulting filter).
278 if (scheme != null) {
279 schemeCut = mSchemeToFilter.get(scheme);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800280 if (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
282
283 // If the intent does not specify any data -- either a MIME type or
284 // a URI -- then we will only be looking for matches against empty
285 // data.
286 if (resolvedType == null && scheme == null && intent.getAction() != null) {
287 firstTypeCut = mActionToFilter.get(intent.getAction());
Joe Onorato8a9b2202010-02-26 18:56:32 -0800288 if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 }
290
Jeff Brown2c376fc2011-01-28 17:34:01 -0800291 FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 if (firstTypeCut != null) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800293 buildResolveList(intent, categories, debug, defaultOnly,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 resolvedType, scheme, firstTypeCut, finalList);
295 }
296 if (secondTypeCut != null) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800297 buildResolveList(intent, categories, debug, defaultOnly,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 resolvedType, scheme, secondTypeCut, finalList);
299 }
300 if (thirdTypeCut != null) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800301 buildResolveList(intent, categories, debug, defaultOnly,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 resolvedType, scheme, thirdTypeCut, finalList);
303 }
304 if (schemeCut != null) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800305 buildResolveList(intent, categories, debug, defaultOnly,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 resolvedType, scheme, schemeCut, finalList);
307 }
308 sortResults(finalList);
309
310 if (debug) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800311 Slog.v(TAG, "Final result list:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 for (R r : finalList) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800313 Slog.v(TAG, " " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 }
315 }
316 return finalList;
317 }
318
319 /**
320 * Control whether the given filter is allowed to go into the result
321 * list. Mainly intended to prevent adding multiple filters for the
322 * same target object.
323 */
324 protected boolean allowFilterResult(F filter, List<R> dest) {
325 return true;
326 }
327
Dianne Hackborne7f97212011-02-24 14:40:20 -0800328 /**
329 * Returns whether the object associated with the given filter is
330 * "stopped," that is whether it should not be included in the result
331 * if the intent requests to excluded stopped objects.
332 */
333 protected boolean isFilterStopped(F filter) {
334 return false;
335 }
336
Dianne Hackbornd4310ac2010-03-16 22:55:08 -0700337 protected String packageForFilter(F filter) {
338 return null;
339 }
340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 protected R newResult(F filter, int match) {
342 return (R)filter;
343 }
344
345 protected void sortResults(List<R> results) {
346 Collections.sort(results, mResolvePrioritySorter);
347 }
348
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700349 protected void dumpFilter(PrintWriter out, String prefix, F filter) {
350 out.print(prefix); out.println(filter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
352
353 private final int register_mime_types(F filter, String prefix) {
354 final Iterator<String> i = filter.typesIterator();
355 if (i == null) {
356 return 0;
357 }
358
359 int num = 0;
360 while (i.hasNext()) {
Kenny Root502e9a42011-01-10 13:48:15 -0800361 String name = i.next();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 num++;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800363 if (localLOGV) Slog.v(TAG, prefix + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 String baseName = name;
365 final int slashpos = name.indexOf('/');
366 if (slashpos > 0) {
367 baseName = name.substring(0, slashpos).intern();
368 } else {
369 name = name + "/*";
370 }
371
372 ArrayList<F> array = mTypeToFilter.get(name);
373 if (array == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800374 //Slog.v(TAG, "Creating new array for " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 array = new ArrayList<F>();
376 mTypeToFilter.put(name, array);
377 }
378 array.add(filter);
379
380 if (slashpos > 0) {
381 array = mBaseTypeToFilter.get(baseName);
382 if (array == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800383 //Slog.v(TAG, "Creating new array for " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 array = new ArrayList<F>();
385 mBaseTypeToFilter.put(baseName, array);
386 }
387 array.add(filter);
388 } else {
389 array = mWildTypeToFilter.get(baseName);
390 if (array == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800391 //Slog.v(TAG, "Creating new array for " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 array = new ArrayList<F>();
393 mWildTypeToFilter.put(baseName, array);
394 }
395 array.add(filter);
396 }
397 }
398
399 return num;
400 }
401
402 private final int unregister_mime_types(F filter, String prefix) {
403 final Iterator<String> i = filter.typesIterator();
404 if (i == null) {
405 return 0;
406 }
407
408 int num = 0;
409 while (i.hasNext()) {
Kenny Root502e9a42011-01-10 13:48:15 -0800410 String name = i.next();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 num++;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800412 if (localLOGV) Slog.v(TAG, prefix + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 String baseName = name;
414 final int slashpos = name.indexOf('/');
415 if (slashpos > 0) {
416 baseName = name.substring(0, slashpos).intern();
417 } else {
418 name = name + "/*";
419 }
420
421 if (!remove_all_objects(mTypeToFilter.get(name), filter)) {
422 mTypeToFilter.remove(name);
423 }
424
425 if (slashpos > 0) {
426 if (!remove_all_objects(mBaseTypeToFilter.get(baseName), filter)) {
427 mBaseTypeToFilter.remove(baseName);
428 }
429 } else {
430 if (!remove_all_objects(mWildTypeToFilter.get(baseName), filter)) {
431 mWildTypeToFilter.remove(baseName);
432 }
433 }
434 }
435 return num;
436 }
437
438 private final int register_intent_filter(F filter, Iterator<String> i,
439 HashMap<String, ArrayList<F>> dest, String prefix) {
440 if (i == null) {
441 return 0;
442 }
443
444 int num = 0;
445 while (i.hasNext()) {
446 String name = i.next();
447 num++;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800448 if (localLOGV) Slog.v(TAG, prefix + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 ArrayList<F> array = dest.get(name);
450 if (array == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800451 //Slog.v(TAG, "Creating new array for " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 array = new ArrayList<F>();
453 dest.put(name, array);
454 }
455 array.add(filter);
456 }
457 return num;
458 }
459
460 private final int unregister_intent_filter(F filter, Iterator<String> i,
461 HashMap<String, ArrayList<F>> dest, String prefix) {
462 if (i == null) {
463 return 0;
464 }
465
466 int num = 0;
467 while (i.hasNext()) {
468 String name = i.next();
469 num++;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800470 if (localLOGV) Slog.v(TAG, prefix + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 if (!remove_all_objects(dest.get(name), filter)) {
472 dest.remove(name);
473 }
474 }
475 return num;
476 }
477
478 private final boolean remove_all_objects(List<F> list, Object object) {
479 if (list != null) {
480 int N = list.size();
481 for (int idx=0; idx<N; idx++) {
482 if (list.get(idx) == object) {
483 list.remove(idx);
484 idx--;
485 N--;
486 }
487 }
488 return N > 0;
489 }
490 return false;
491 }
492
Jeff Brown2c376fc2011-01-28 17:34:01 -0800493 private static FastImmutableArraySet<String> getFastIntentCategories(Intent intent) {
494 final Set<String> categories = intent.getCategories();
495 if (categories == null) {
496 return null;
497 }
498 return new FastImmutableArraySet<String>(categories.toArray(new String[categories.size()]));
499 }
500
501 private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
502 boolean debug, boolean defaultOnly,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 String resolvedType, String scheme, List<F> src, List<R> dest) {
Jeff Brown2c376fc2011-01-28 17:34:01 -0800504 final String action = intent.getAction();
505 final Uri data = intent.getData();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506
Dianne Hackborne7f97212011-02-24 14:40:20 -0800507 final boolean excludingStopped = intent.isExcludingStopped();
508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 final int N = src != null ? src.size() : 0;
510 boolean hasNonDefaults = false;
511 int i;
512 for (i=0; i<N; i++) {
513 F filter = src.get(i);
514 int match;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800515 if (debug) Slog.v(TAG, "Matching against filter " + filter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516
Dianne Hackborne7f97212011-02-24 14:40:20 -0800517 if (excludingStopped && isFilterStopped(filter)) {
518 if (debug) {
519 Slog.v(TAG, " Filter's target is stopped; skipping");
520 }
521 continue;
522 }
523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 // Do we already have this one?
525 if (!allowFilterResult(filter, dest)) {
526 if (debug) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800527 Slog.v(TAG, " Filter's target already added");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529 continue;
530 }
531
Jeff Brown2c376fc2011-01-28 17:34:01 -0800532 match = filter.match(action, resolvedType, scheme, data, categories, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 if (match >= 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800534 if (debug) Slog.v(TAG, " Filter matched! match=0x" +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 Integer.toHexString(match));
536 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
537 final R oneResult = newResult(filter, match);
538 if (oneResult != null) {
539 dest.add(oneResult);
540 }
541 } else {
542 hasNonDefaults = true;
543 }
544 } else {
545 if (debug) {
546 String reason;
547 switch (match) {
548 case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
549 case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
550 case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
551 case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
552 default: reason = "unknown reason"; break;
553 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800554 Slog.v(TAG, " Filter did not match: " + reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 }
556 }
557 }
558
559 if (dest.size() == 0 && hasNonDefaults) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800560 Slog.w(TAG, "resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 }
562 }
563
564 // Sorts a List of IntentFilter objects into descending priority order.
565 private static final Comparator mResolvePrioritySorter = new Comparator() {
566 public int compare(Object o1, Object o2) {
Kenny Root502e9a42011-01-10 13:48:15 -0800567 final int q1 = ((IntentFilter) o1).getPriority();
568 final int q2 = ((IntentFilter) o2).getPriority();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);
570 }
571 };
572
573 /**
574 * All filters that have been registered.
575 */
576 private final HashSet<F> mFilters = new HashSet<F>();
577
578 /**
579 * All of the MIME types that have been registered, such as "image/jpeg",
580 * "image/*", or "{@literal *}/*".
581 */
582 private final HashMap<String, ArrayList<F>> mTypeToFilter
583 = new HashMap<String, ArrayList<F>>();
584
585 /**
586 * The base names of all of all fully qualified MIME types that have been
587 * registered, such as "image" or "*". Wild card MIME types such as
588 * "image/*" will not be here.
589 */
590 private final HashMap<String, ArrayList<F>> mBaseTypeToFilter
591 = new HashMap<String, ArrayList<F>>();
592
593 /**
594 * The base names of all of the MIME types with a sub-type wildcard that
595 * have been registered. For example, a filter with "image/*" will be
596 * included here as "image" but one with "image/jpeg" will not be
597 * included here. This also includes the "*" for the "{@literal *}/*"
598 * MIME type.
599 */
600 private final HashMap<String, ArrayList<F>> mWildTypeToFilter
601 = new HashMap<String, ArrayList<F>>();
602
603 /**
604 * All of the URI schemes (such as http) that have been registered.
605 */
606 private final HashMap<String, ArrayList<F>> mSchemeToFilter
607 = new HashMap<String, ArrayList<F>>();
608
609 /**
610 * All of the actions that have been registered, but only those that did
611 * not specify data.
612 */
613 private final HashMap<String, ArrayList<F>> mActionToFilter
614 = new HashMap<String, ArrayList<F>>();
615
616 /**
617 * All of the actions that have been registered and specified a MIME type.
618 */
619 private final HashMap<String, ArrayList<F>> mTypedActionToFilter
620 = new HashMap<String, ArrayList<F>>();
621}
622