ShortcutsProvider.java revision 86e26bb90fe12a2a1daf7785767fbde8d75647ed
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
17package com.android.quicksearchbox;
18
19import android.app.SearchManager;
20import android.content.ComponentName;
21import android.content.ContentProvider;
22import android.content.ContentValues;
23import android.content.UriMatcher;
24import android.content.pm.PackageManager;
25import android.database.Cursor;
26import android.net.Uri;
27import android.os.Binder;
28import android.text.TextUtils;
29import android.util.Log;
30
31/**
32 * Handles broadcast intents for adding shortcuts to QSB.
33 */
34public class ShortcutsProvider extends ContentProvider {
35
36    private static final boolean DBG = true;
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 SHORTCUTS = 0;
42
43    private UriMatcher mUriMatcher;
44
45    @Override
46    public boolean onCreate() {
47        mUriMatcher = buildUriMatcher();
48        return true;
49    }
50
51    private UriMatcher buildUriMatcher() {
52        String authority = getAuthority();
53        UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
54        matcher.addURI(authority, "shortcuts", SHORTCUTS);
55        return matcher;
56    }
57
58    private String getAuthority() {
59        return getContext().getPackageName() + ".shortcuts";
60    }
61
62    @Override
63    public String getType(Uri uri) {
64        switch (mUriMatcher.match(uri)) {
65            case SHORTCUTS:
66                return SearchManager.SUGGEST_MIME_TYPE;
67            default:
68                throw new IllegalArgumentException("Unknown URI: " + uri);
69        }
70    }
71
72    @Override
73    public Uri insert(Uri uri, ContentValues values) {
74        switch (mUriMatcher.match(uri)) {
75            case SHORTCUTS:
76                addShortcut(values);
77                return null;
78            default:
79                throw new IllegalArgumentException("Unknown URI: " + uri);
80        }
81    }
82
83    @Override
84    public int delete(Uri uri, String selection, String[] selectionArgs) {
85        throw new UnsupportedOperationException();
86    }
87
88    @Override
89    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
90            String sortOrder) {
91        throw new UnsupportedOperationException();
92    }
93
94    @Override
95    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
96        throw new UnsupportedOperationException();
97    }
98
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
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        DataSuggestionCursor cursor = new DataSuggestionCursor(userQuery);
132        cursor.add(makeSuggestion(source, shortcut));
133        getShortcutRepository().reportClick(cursor, 0);
134    }
135
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
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
180    private static boolean unboxBoolean(Boolean value, boolean defValue) {
181        return value == null ? defValue : value;
182    }
183
184    private QsbApplication getQsbApplication() {
185        return (QsbApplication) getContext().getApplicationContext();
186    }
187
188    private ShortcutRepository getShortcutRepository() {
189        return getQsbApplication().getShortcutRepository();
190    }
191
192    private Corpora getCorpora() {
193        return getQsbApplication().getCorpora();
194    }
195
196}
197