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 
SuggestionUtils()31     private SuggestionUtils() {
32     }
33 
getSuggestionIntent(SuggestionCursor suggestion, Bundle appSearchData)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      */
getSuggestionKey(Suggestion suggestion)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 
makeKeyComponent(String str)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
normalizeUrl(String url)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