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