blob: 688d3f1ef1656d4ffba100a560cd94bff82228eb [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quicksearchbox;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.text.TextUtils;
import android.util.Log;
/**
* Handles broadcast intents for adding shortcuts to QSB.
*/
public class ShortcutsProvider extends ContentProvider {
private static final boolean DBG = false;
private static final String TAG = "QSB.ExternalShortcutReceiver";
public static final String EXTRA_SHORTCUT_SOURCE = "shortcut_source";
private static final int URI_CODE_SHORTCUTS = 0;
private UriMatcher mUriMatcher;
@Override
public boolean onCreate() {
mUriMatcher = buildUriMatcher();
return true;
}
private UriMatcher buildUriMatcher() {
String authority = getAuthority();
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI(authority, "shortcuts", URI_CODE_SHORTCUTS);
return matcher;
}
private String getAuthority() {
return getContext().getPackageName() + ".shortcuts";
}
@Override
public String getType(Uri uri) {
switch (mUriMatcher.match(uri)) {
case URI_CODE_SHORTCUTS:
return SearchManager.SUGGEST_MIME_TYPE;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (mUriMatcher.match(uri)) {
case URI_CODE_SHORTCUTS:
addShortcut(values);
return null;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
throw new UnsupportedOperationException();
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
private void addShortcut(final ContentValues shortcut) {
String sourceName = shortcut.getAsString(EXTRA_SHORTCUT_SOURCE);
if (TextUtils.isEmpty(sourceName)) {
Log.e(TAG, "Missing " + EXTRA_SHORTCUT_SOURCE);
return;
}
String sourceAction = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
if (Intent.ACTION_WEB_SEARCH.equals(sourceAction)) {
if (DBG) {
Log.d(TAG, "Ignoring shortcut from " + sourceName +
"because its intent action was ACTION_WEB_SEARCH.");
}
return;
}
final ComponentName sourceComponent = ComponentName.unflattenFromString(sourceName);
if (!checkCallingPackage(sourceComponent.getPackageName())) {
Log.w(TAG, "Got shortcut for " + sourceComponent + " from a different process");
return;
}
getQsbApplication().runOnUiThread(new Runnable() {
public void run() {
storeShortcut(sourceComponent, shortcut);
}
});
}
// Called on the main thread
private void storeShortcut(ComponentName sourceComponent, ContentValues shortcut) {
if (DBG) Log.d(TAG, "Adding (PID: " + Binder.getCallingPid() + "): " + shortcut);
Source source = getCorpora().getSource(sourceComponent.flattenToShortString());
if (source == null) {
Log.w(TAG, "Unknown shortcut source " + sourceComponent);
return;
}
String userQuery = shortcut.getAsString(SearchManager.USER_QUERY);
if (userQuery == null) userQuery = "";
ListSuggestionCursor cursor = new ListSuggestionCursor(userQuery);
cursor.add(makeSuggestion(source, shortcut));
getShortcutRepository().reportClick(cursor, 0);
}
private boolean checkCallingPackage(String packageName) {
int callingUid = Binder.getCallingUid();
PackageManager pm = getContext().getPackageManager();
String[] uidPkgs = pm.getPackagesForUid(callingUid);
if (uidPkgs == null) return false;
for (String uidPkg : uidPkgs) {
if (packageName.equals(uidPkg)) return true;
}
return false;
}
private SuggestionData makeSuggestion(Source source, ContentValues shortcut) {
String format = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_FORMAT);
String text1 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_1);
String text2 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_2);
String text2Url = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
String icon1 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_ICON_1);
String icon2 = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_ICON_2);
String shortcutId = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
boolean spinnerWhileRefreshing = unboxBoolean(
shortcut.getAsBoolean(SearchManager.SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING),
false);
String intentAction = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
String intentData = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_DATA);
String intentExtraData =
shortcut.getAsString(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
String query = shortcut.getAsString(SearchManager.SUGGEST_COLUMN_QUERY);
SuggestionData suggestion = new SuggestionData(source);
suggestion.setFormat(format);
suggestion.setText1(text1);
suggestion.setText2(text2);
suggestion.setText2Url(text2Url);
suggestion.setIcon1(icon1);
suggestion.setIcon2(icon2);
suggestion.setShortcutId(shortcutId);
suggestion.setSpinnerWhileRefreshing(spinnerWhileRefreshing);
suggestion.setIntentAction(intentAction);
suggestion.setIntentData(intentData);
suggestion.setIntentExtraData(intentExtraData);
suggestion.setSuggestionQuery(query);
return suggestion;
}
private static boolean unboxBoolean(Boolean value, boolean defValue) {
return value == null ? defValue : value;
}
private QsbApplication getQsbApplication() {
return QsbApplication.get(getContext());
}
private ShortcutRepository getShortcutRepository() {
return getQsbApplication().getShortcutRepository();
}
private Corpora getCorpora() {
return getQsbApplication().getCorpora();
}
}