1 /* 2 * Copyright (C) 2010 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.quicksearchbox; 18 19 import com.google.common.annotations.VisibleForTesting; 20 21 import android.app.SearchManager; 22 import android.content.Intent; 23 import android.net.Uri; 24 import android.os.Bundle; 25 26 /** 27 * Some utilities for suggestions. 28 */ 29 public class SuggestionUtils { 30 31 private SuggestionUtils() { 32 } 33 34 public static Intent getSuggestionIntent(SuggestionCursor suggestion, Bundle appSearchData) { 35 String action = suggestion.getSuggestionIntentAction(); 36 37 String data = suggestion.getSuggestionIntentDataString(); 38 String query = suggestion.getSuggestionQuery(); 39 String userQuery = suggestion.getUserQuery(); 40 String extraData = suggestion.getSuggestionIntentExtraData(); 41 42 // Now build the Intent 43 Intent intent = new Intent(action); 44 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 45 // We need CLEAR_TOP to avoid reusing an old task that has other activities 46 // on top of the one we want. 47 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 48 if (data != null) { 49 intent.setData(Uri.parse(data)); 50 } 51 intent.putExtra(SearchManager.USER_QUERY, userQuery); 52 if (query != null) { 53 intent.putExtra(SearchManager.QUERY, query); 54 } 55 if (extraData != null) { 56 intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); 57 } 58 if (appSearchData != null) { 59 intent.putExtra(SearchManager.APP_DATA, appSearchData); 60 } 61 62 intent.setComponent(suggestion.getSuggestionIntentComponent()); 63 return intent; 64 } 65 66 /** 67 * Gets a unique key that identifies a suggestion. This is used to avoid 68 * duplicate suggestions. 69 */ 70 public static String getSuggestionKey(Suggestion suggestion) { 71 String action = makeKeyComponent(suggestion.getSuggestionIntentAction()); 72 String data = makeKeyComponent(normalizeUrl(suggestion.getSuggestionIntentDataString())); 73 String query = makeKeyComponent(normalizeUrl(suggestion.getSuggestionQuery())); 74 // calculating accurate size of string builder avoids an allocation vs starting with 75 // the default size and having to expand. 76 int size = action.length() + 2 + data.length() + query.length(); 77 return new StringBuilder(size) 78 .append(action) 79 .append('#') 80 .append(data) 81 .append('#') 82 .append(query) 83 .toString(); 84 } 85 86 private static String makeKeyComponent(String str) { 87 return str == null ? "" : str; 88 } 89 90 private static final String SCHEME_SEPARATOR = "://"; 91 private static final String DEFAULT_SCHEME = "http"; 92 93 /** 94 * Simple url normalization that adds http:// if no scheme exists, and 95 * strips empty paths, e.g., 96 * www.google.com/ -> http://www.google.com. Used to prevent obvious 97 * duplication of nav suggestions, bookmarks and urls entered by the user. 98 */ 99 @VisibleForTesting 100 static String normalizeUrl(String url) { 101 String normalized; 102 if (url != null) { 103 int start; 104 int schemePos = url.indexOf(SCHEME_SEPARATOR); 105 if (schemePos == -1) { 106 // no scheme - add the default 107 normalized = DEFAULT_SCHEME + SCHEME_SEPARATOR + url; 108 start = DEFAULT_SCHEME.length() + SCHEME_SEPARATOR.length(); 109 } else { 110 normalized = url; 111 start = schemePos + SCHEME_SEPARATOR.length(); 112 } 113 int end = normalized.length(); 114 if (normalized.indexOf('/', start) == end - 1) { 115 end--; 116 } 117 return normalized.substring(0, end); 118 } 119 return url; 120 } 121 122 } 123