• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.app.SearchManager;
20 import android.content.ComponentName;
21 import android.content.ContentProvider;
22 import android.content.ContentValues;
23 import android.content.UriMatcher;
24 import android.content.pm.PackageManager;
25 import android.database.Cursor;
26 import android.net.Uri;
27 import android.os.Binder;
28 import android.text.TextUtils;
29 import android.util.Log;
30 
31 /**
32  * Handles broadcast intents for adding shortcuts to QSB.
33  */
34 public class ShortcutsProvider extends ContentProvider {
35 
36     private static final boolean DBG = false;
37     private static final String TAG = "QSB.ExternalShortcutReceiver";
38 
39     public static final String EXTRA_SHORTCUT_SOURCE = "shortcut_source";
40 
41     private static final int URI_CODE_SHORTCUTS = 0;
42 
43     private UriMatcher mUriMatcher;
44 
45     @Override
onCreate()46     public boolean onCreate() {
47         mUriMatcher = buildUriMatcher();
48         return true;
49     }
50 
buildUriMatcher()51     private UriMatcher buildUriMatcher() {
52         String authority = getAuthority();
53         UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
54         matcher.addURI(authority, "shortcuts", URI_CODE_SHORTCUTS);
55         return matcher;
56     }
57 
getAuthority()58     private String getAuthority() {
59         return getContext().getPackageName() + ".shortcuts";
60     }
61 
62     @Override
getType(Uri uri)63     public String getType(Uri uri) {
64         switch (mUriMatcher.match(uri)) {
65             case URI_CODE_SHORTCUTS:
66                 return SearchManager.SUGGEST_MIME_TYPE;
67             default:
68                 throw new IllegalArgumentException("Unknown URI: " + uri);
69         }
70     }
71 
72     @Override
insert(Uri uri, ContentValues values)73     public Uri insert(Uri uri, ContentValues values) {
74         switch (mUriMatcher.match(uri)) {
75             case URI_CODE_SHORTCUTS:
76                 addShortcut(values);
77                 return null;
78             default:
79                 throw new IllegalArgumentException("Unknown URI: " + uri);
80         }
81     }
82 
83     @Override
delete(Uri uri, String selection, String[] selectionArgs)84     public int delete(Uri uri, String selection, String[] selectionArgs) {
85         throw new UnsupportedOperationException();
86     }
87 
88     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)89     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
90             String sortOrder) {
91         throw new UnsupportedOperationException();
92     }
93 
94     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)95     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
96         throw new UnsupportedOperationException();
97     }
98 
addShortcut(final ContentValues shortcut)99     private void addShortcut(final ContentValues shortcut) {
100         String sourceName = shortcut.getAsString(EXTRA_SHORTCUT_SOURCE);
101         if (TextUtils.isEmpty(sourceName)) {
102             Log.e(TAG, "Missing " + EXTRA_SHORTCUT_SOURCE);
103             return;
104         }
105         final ComponentName sourceComponent = ComponentName.unflattenFromString(sourceName);
106         if (!checkCallingPackage(sourceComponent.getPackageName())) {
107             Log.w(TAG, "Got shortcut for " + sourceComponent + " from a different process");
108             return;
109         }
110 
111         getQsbApplication().runOnUiThread(new Runnable() {
112             public void run() {
113                 storeShortcut(sourceComponent, shortcut);
114             }
115         });
116     }
117 
118     // Called on the main thread
storeShortcut(ComponentName sourceComponent, ContentValues shortcut)119     private void storeShortcut(ComponentName sourceComponent, ContentValues shortcut) {
120         if (DBG) Log.d(TAG, "Adding (PID: " + Binder.getCallingPid() + "): " + shortcut);
121 
122         Source source = getCorpora().getSource(sourceComponent.flattenToShortString());
123         if (source == null) {
124             Log.w(TAG, "Unknown shortcut source " + sourceComponent);
125             return;
126         }
127 
128         String userQuery = shortcut.getAsString(SearchManager.USER_QUERY);
129         if (userQuery == null) userQuery = "";
130 
131         ListSuggestionCursor cursor = new ListSuggestionCursor(userQuery);
132         cursor.add(makeSuggestion(source, shortcut));
133         getShortcutRepository().reportClick(cursor, 0);
134     }
135 
checkCallingPackage(String packageName)136     private boolean checkCallingPackage(String packageName) {
137         int callingUid = Binder.getCallingUid();
138         PackageManager pm = getContext().getPackageManager();
139         String[] uidPkgs = pm.getPackagesForUid(callingUid);
140         if (uidPkgs == null) return false;
141         for (String uidPkg : uidPkgs) {
142             if (packageName.equals(uidPkg)) return true;
143         }
144         return false;
145     }
146 
makeSuggestion(Source source, ContentValues shortcut)147     private SuggestionData makeSuggestion(Source source, ContentValues shortcut) {
148         String format = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_FORMAT);
149         String text1 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_1);
150         String text2 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_2);
151         String text2Url = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
152         String icon1 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_ICON_1);
153         String icon2 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_ICON_2);
154         String shortcutId = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
155         boolean spinnerWhileRefreshing = unboxBoolean(
156                 shortcut.getAsBoolean(SearchManager.SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING),
157                 false);
158         String intentAction = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
159         String intentData = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_DATA);
160         String intentExtraData =
161                 shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
162         String query = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_QUERY);
163 
164         SuggestionData suggestion = new SuggestionData(source);
165         suggestion.setFormat(format);
166         suggestion.setText1(text1);
167         suggestion.setText2(text2);
168         suggestion.setText2Url(text2Url);
169         suggestion.setIcon1(icon1);
170         suggestion.setIcon2(icon2);
171         suggestion.setShortcutId(shortcutId);
172         suggestion.setSpinnerWhileRefreshing(spinnerWhileRefreshing);
173         suggestion.setIntentAction(intentAction);
174         suggestion.setIntentData(intentData);
175         suggestion.setIntentExtraData(intentExtraData);
176         suggestion.setSuggestionQuery(query);
177         return suggestion;
178     }
179 
unboxBoolean(Boolean value, boolean defValue)180     private static boolean unboxBoolean(Boolean value, boolean defValue) {
181         return value == null ? defValue : value;
182     }
183 
getQsbApplication()184     private QsbApplication getQsbApplication() {
185         return QsbApplication.get(getContext());
186     }
187 
getShortcutRepository()188     private ShortcutRepository getShortcutRepository() {
189         return getQsbApplication().getShortcutRepository();
190     }
191 
getCorpora()192     private Corpora getCorpora() {
193         return getQsbApplication().getCorpora();
194     }
195 
196 }
197