summaryrefslogtreecommitdiff
path: root/src/com/android/providers/applications/ApplicationsProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/applications/ApplicationsProvider.java')
-rw-r--r--src/com/android/providers/applications/ApplicationsProvider.java702
1 files changed, 0 insertions, 702 deletions
diff --git a/src/com/android/providers/applications/ApplicationsProvider.java b/src/com/android/providers/applications/ApplicationsProvider.java
deleted file mode 100644
index 128fe2f..0000000
--- a/src/com/android/providers/applications/ApplicationsProvider.java
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * Copyright (C) 2009 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.providers.applications;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.PkgUsageStats;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.SearchManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.UriMatcher;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.net.Uri;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Applications;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.lang.Runnable;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.common.annotations.VisibleForTesting;
-
-/**
- * Fetches the list of applications installed on the phone to provide search suggestions.
- * If the functionality of this provider changes, the documentation at
- * {@link android.provider.Applications} should be updated.
- *
- * TODO: this provider should be moved to the Launcher, which contains similar logic to keep an up
- * to date list of installed applications. Alternatively, Launcher could be updated to use this
- * provider.
- */
-public class ApplicationsProvider extends ContentProvider {
-
- private static final boolean DBG = false;
-
- private static final String TAG = "ApplicationsProvider";
-
- private static final int SEARCH_SUGGEST = 0;
- private static final int SHORTCUT_REFRESH = 1;
- private static final int SEARCH = 2;
-
- private static final UriMatcher sURIMatcher = buildUriMatcher();
-
- private static final int THREAD_PRIORITY = android.os.Process.THREAD_PRIORITY_BACKGROUND;
-
- // Messages for mHandler
- private static final int MSG_UPDATE_ALL = 0;
- private static final int MSG_UPDATE_PACKAGE = 1;
-
- public static final String _ID = "_id";
- public static final String NAME = "name";
- public static final String DESCRIPTION = "description";
- public static final String PACKAGE = "package";
- public static final String CLASS = "class";
- public static final String ICON = "icon";
- public static final String LAUNCH_COUNT = "launch_count";
- public static final String LAST_RESUME_TIME = "last_resume_time";
-
- // A query parameter to refresh application statistics. Used by QSB.
- public static final String REFRESH_STATS = "refresh";
-
- private static final String APPLICATIONS_TABLE = "applications";
-
- private static final String APPLICATIONS_LOOKUP_JOIN =
- "applicationsLookup JOIN " + APPLICATIONS_TABLE + " ON"
- + " applicationsLookup.source = " + APPLICATIONS_TABLE + "." + _ID;
-
- private static final HashMap<String, String> sSearchSuggestionsProjectionMap =
- buildSuggestionsProjectionMap(false);
- private static final HashMap<String, String> sGlobalSearchSuggestionsProjectionMap =
- buildSuggestionsProjectionMap(true);
- private static final HashMap<String, String> sSearchProjectionMap =
- buildSearchProjectionMap();
-
- /**
- * An in-memory database storing the details of applications installed on
- * the device. Populated when the ApplicationsProvider is launched.
- */
- private SQLiteDatabase mDb;
-
- // Handler that runs DB updates.
- private Handler mHandler;
-
- /**
- * We delay application updates by this many millis to avoid doing more than one update to the
- * applications list within this window.
- */
- private static final long UPDATE_DELAY_MILLIS = 1000L;
-
- private static UriMatcher buildUriMatcher() {
- UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
- matcher.addURI(Applications.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
- SEARCH_SUGGEST);
- matcher.addURI(Applications.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
- SEARCH_SUGGEST);
- matcher.addURI(Applications.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT,
- SHORTCUT_REFRESH);
- matcher.addURI(Applications.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*",
- SHORTCUT_REFRESH);
- matcher.addURI(Applications.AUTHORITY, Applications.SEARCH_PATH,
- SEARCH);
- matcher.addURI(Applications.AUTHORITY, Applications.SEARCH_PATH + "/*",
- SEARCH);
- return matcher;
- }
-
- /**
- * Updates applications list when packages are added/removed.
- *
- * TODO: Maybe this should listen for changes to individual apps instead.
- */
- private class MyPackageMonitor extends PackageMonitor {
- @Override
- public void onSomePackagesChanged() {
- postUpdateAll();
- }
-
- @Override
- public void onPackageModified(String packageName) {
- postUpdatePackage(packageName);
- }
- }
-
- // Broadcast receiver for updating applications list when the locale changes.
- private BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
- if (DBG) Log.d(TAG, "locale changed");
- postUpdateAll();
- }
- }
- };
-
- @Override
- public boolean onCreate() {
- createDatabase();
- // Start thread that runs app updates
- HandlerThread thread = new HandlerThread("ApplicationsProviderUpdater", THREAD_PRIORITY);
- thread.start();
- mHandler = createHandler(thread.getLooper());
- // Kick off first apps update
- postUpdateAll();
- // Listen for package changes
- new MyPackageMonitor().register(getContext(), null, true);
- // Listen for locale changes
- IntentFilter localeFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
- getContext().registerReceiver(mLocaleChangeReceiver, localeFilter);
- return true;
- }
-
- @VisibleForTesting
- Handler createHandler(Looper looper) {
- return new UpdateHandler(looper);
- }
-
- @VisibleForTesting
- class UpdateHandler extends Handler {
-
- public UpdateHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_ALL:
- updateApplicationsList(null);
- break;
- case MSG_UPDATE_PACKAGE:
- updateApplicationsList((String) msg.obj);
- break;
- default:
- Log.e(TAG, "Unknown message: " + msg.what);
- break;
- }
- }
- }
-
- /**
- * Posts an update to run on the DB update thread.
- */
- private void postUpdateAll() {
- // Clear pending updates
- mHandler.removeMessages(MSG_UPDATE_ALL);
- // Post a new update
- Message msg = Message.obtain();
- msg.what = MSG_UPDATE_ALL;
- mHandler.sendMessageDelayed(msg, UPDATE_DELAY_MILLIS);
- }
-
- private void postUpdatePackage(String packageName) {
- Message msg = Message.obtain();
- msg.what = MSG_UPDATE_PACKAGE;
- msg.obj = packageName;
- mHandler.sendMessageDelayed(msg, UPDATE_DELAY_MILLIS);
- }
-
- // ----------
- // END ASYC UPDATE CODE
- // ----------
-
- /**
- * Creates an in-memory database for storing application info.
- */
- private void createDatabase() {
- mDb = SQLiteDatabase.create(null);
- mDb.execSQL("CREATE TABLE IF NOT EXISTS " + APPLICATIONS_TABLE + " (" +
- _ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- NAME + " TEXT COLLATE LOCALIZED," +
- DESCRIPTION + " description TEXT," +
- PACKAGE + " TEXT," +
- CLASS + " TEXT," +
- ICON + " TEXT," +
- LAUNCH_COUNT + " INTEGER DEFAULT 0," +
- LAST_RESUME_TIME + " INTEGER DEFAULT 0" +
- ");");
- // Needed for efficient update and remove
- mDb.execSQL("CREATE INDEX applicationsComponentIndex ON " + APPLICATIONS_TABLE + " ("
- + PACKAGE + "," + CLASS + ");");
- // Maps token from the app name to records in the applications table
- mDb.execSQL("CREATE TABLE applicationsLookup (" +
- "token TEXT," +
- "source INTEGER REFERENCES " + APPLICATIONS_TABLE + "(" + _ID + ")," +
- "token_index INTEGER" +
- ");");
- mDb.execSQL("CREATE INDEX applicationsLookupIndex ON applicationsLookup (" +
- "token," +
- "source" +
- ");");
- // Triggers to keep the applicationsLookup table up to date
- mDb.execSQL("CREATE TRIGGER applicationsLookup_update UPDATE OF " + NAME + " ON " +
- APPLICATIONS_TABLE + " " +
- "BEGIN " +
- "DELETE FROM applicationsLookup WHERE source = new." + _ID + ";" +
- "SELECT _TOKENIZE('applicationsLookup', new." + _ID + ", new." + NAME + ", ' ', 1);"
- + "END");
- mDb.execSQL("CREATE TRIGGER applicationsLookup_insert AFTER INSERT ON " +
- APPLICATIONS_TABLE + " " +
- "BEGIN " +
- "SELECT _TOKENIZE('applicationsLookup', new." + _ID + ", new." + NAME + ", ' ', 1);"
- + "END");
- mDb.execSQL("CREATE TRIGGER applicationsLookup_delete DELETE ON " +
- APPLICATIONS_TABLE + " " +
- "BEGIN " +
- "DELETE FROM applicationsLookup WHERE source = old." + _ID + ";" +
- "END");
- }
-
- /**
- * This will always return {@link SearchManager#SUGGEST_MIME_TYPE} as this
- * provider is purely to provide suggestions.
- */
- @Override
- public String getType(Uri uri) {
- switch (sURIMatcher.match(uri)) {
- case SEARCH_SUGGEST:
- return SearchManager.SUGGEST_MIME_TYPE;
- case SHORTCUT_REFRESH:
- return SearchManager.SHORTCUT_MIME_TYPE;
- case SEARCH:
- return Applications.APPLICATION_DIR_TYPE;
- default:
- throw new IllegalArgumentException("URL " + uri + " doesn't support querying.");
- }
- }
-
- @Override
- public Cursor query(Uri uri, String[] projectionIn, String selection,
- String[] selectionArgs, String sortOrder) {
- return query(uri, projectionIn, selection, selectionArgs, sortOrder, null);
- }
-
- /**
- * Queries for a given search term and returns a cursor containing
- * suggestions ordered by best match.
- */
- @Override
- public Cursor query(Uri uri, String[] projectionIn, String selection,
- String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
- if (DBG) Log.d(TAG, "query(" + uri + ")");
-
- if (!TextUtils.isEmpty(selection)) {
- throw new IllegalArgumentException("selection not allowed for " + uri);
- }
- if (selectionArgs != null && selectionArgs.length != 0) {
- throw new IllegalArgumentException("selectionArgs not allowed for " + uri);
- }
- if (!TextUtils.isEmpty(sortOrder)) {
- throw new IllegalArgumentException("sortOrder not allowed for " + uri);
- }
-
- switch (sURIMatcher.match(uri)) {
- case SEARCH_SUGGEST: {
- String query = null;
- if (uri.getPathSegments().size() > 1) {
- query = uri.getLastPathSegment().toLowerCase();
- }
- if (uri.getQueryParameter(REFRESH_STATS) != null) {
- updateUsageStats();
- }
- return getSuggestions(query, projectionIn, cancellationSignal);
- }
- case SHORTCUT_REFRESH: {
- String shortcutId = null;
- if (uri.getPathSegments().size() > 1) {
- shortcutId = uri.getLastPathSegment();
- }
- return refreshShortcut(shortcutId, projectionIn);
- }
- case SEARCH: {
- String query = null;
- if (uri.getPathSegments().size() > 1) {
- query = uri.getLastPathSegment().toLowerCase();
- }
- return getSearchResults(query, projectionIn, cancellationSignal);
- }
- default:
- throw new IllegalArgumentException("URL " + uri + " doesn't support querying.");
- }
- }
-
- private Cursor getSuggestions(String query, String[] projectionIn,
- CancellationSignal cancellationSignal) {
- Map<String, String> projectionMap = sSearchSuggestionsProjectionMap;
- // No zero-query suggestions or launch times except for global search,
- // to avoid leaking info about apps that have been used.
- if (hasGlobalSearchPermission()) {
- projectionMap = sGlobalSearchSuggestionsProjectionMap;
- } else if (TextUtils.isEmpty(query)) {
- return null;
- }
- return searchApplications(query, projectionIn, projectionMap, cancellationSignal);
- }
-
- /**
- * Refreshes the shortcut of an application.
- *
- * @param shortcutId Flattened component name of an activity.
- */
- private Cursor refreshShortcut(String shortcutId, String[] projectionIn) {
- ComponentName component = ComponentName.unflattenFromString(shortcutId);
- if (component == null) {
- Log.w(TAG, "Bad shortcut id: " + shortcutId);
- return null;
- }
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(APPLICATIONS_TABLE);
- qb.setProjectionMap(sSearchSuggestionsProjectionMap);
- qb.appendWhere("package = ? AND class = ?");
- String[] selectionArgs = { component.getPackageName(), component.getClassName() };
- Cursor cursor = qb.query(mDb, projectionIn, null, selectionArgs, null, null, null);
- if (DBG) Log.d(TAG, "Returning " + cursor.getCount() + " results for shortcut refresh.");
- return cursor;
- }
-
- private Cursor getSearchResults(String query, String[] projectionIn,
- CancellationSignal cancellationSignal) {
- return searchApplications(query, projectionIn, sSearchProjectionMap, cancellationSignal);
- }
-
- private Cursor searchApplications(String query, String[] projectionIn,
- Map<String, String> columnMap, CancellationSignal cancelationSignal) {
- final boolean zeroQuery = TextUtils.isEmpty(query);
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(APPLICATIONS_LOOKUP_JOIN);
- qb.setProjectionMap(columnMap);
- String orderBy = null;
- if (!zeroQuery) {
- qb.appendWhere(buildTokenFilter(query));
- } else {
- if (hasGlobalSearchPermission()) {
- qb.appendWhere(LAST_RESUME_TIME + " > 0");
- }
- }
- if (!hasGlobalSearchPermission()) {
- orderBy = getOrderBy(zeroQuery);
- }
- // don't return duplicates when there are two matching tokens for an app
- String groupBy = APPLICATIONS_TABLE + "." + _ID;
- Cursor cursor = qb.query(mDb, projectionIn, null, null, groupBy, null, orderBy, null,
- cancelationSignal);
- if (DBG) Log.d(TAG, "Returning " + cursor.getCount() + " results for " + query);
- return cursor;
- }
-
- private String getOrderBy(boolean zeroQuery) {
- // order first by whether it a full prefix match, then by launch
- // count (if allowed, frequently used apps rank higher), then name
- // MIN(token_index) != 0 is true for non-full prefix matches,
- // and since false (0) < true(1), this expression makes sure
- // that full prefix matches come first.
- StringBuilder orderBy = new StringBuilder();
- if (!zeroQuery) {
- orderBy.append("MIN(token_index) != 0, ");
- }
-
- if (hasGlobalSearchPermission()) {
- orderBy.append(LAST_RESUME_TIME + " DESC, ");
- }
-
- orderBy.append(NAME);
-
- return orderBy.toString();
- }
-
- @SuppressWarnings("deprecation")
- private String buildTokenFilter(String filterParam) {
- StringBuilder filter = new StringBuilder("token GLOB ");
- // NOTE: Query parameters won't work here since the SQL compiler
- // needs to parse the actual string to know that it can use the
- // index to do a prefix scan.
- DatabaseUtils.appendEscapedSQLString(filter,
- DatabaseUtils.getHexCollationKey(filterParam) + "*");
- return filter.toString();
- }
-
- private static HashMap<String, String> buildSuggestionsProjectionMap(boolean forGlobalSearch) {
- HashMap<String, String> map = new HashMap<String, String>();
- addProjection(map, Applications.ApplicationColumns._ID, _ID);
- addProjection(map, SearchManager.SUGGEST_COLUMN_TEXT_1, NAME);
- addProjection(map, SearchManager.SUGGEST_COLUMN_TEXT_2, DESCRIPTION);
- addProjection(map, SearchManager.SUGGEST_COLUMN_INTENT_DATA,
- "'content://" + Applications.AUTHORITY + "/applications/'"
- + " || " + PACKAGE + " || '/' || " + CLASS);
- addProjection(map, SearchManager.SUGGEST_COLUMN_ICON_1, ICON);
- addProjection(map, SearchManager.SUGGEST_COLUMN_ICON_2, "NULL");
- addProjection(map, SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
- PACKAGE + " || '/' || " + CLASS);
- if (forGlobalSearch) {
- addProjection(map, SearchManager.SUGGEST_COLUMN_LAST_ACCESS_HINT,
- LAST_RESUME_TIME);
- }
- return map;
- }
-
- private static HashMap<String, String> buildSearchProjectionMap() {
- HashMap<String, String> map = new HashMap<String, String>();
- addProjection(map, Applications.ApplicationColumns._ID, _ID);
- addProjection(map, Applications.ApplicationColumns.NAME, NAME);
- addProjection(map, Applications.ApplicationColumns.ICON, ICON);
- addProjection(map, Applications.ApplicationColumns.URI,
- "'content://" + Applications.AUTHORITY + "/applications/'"
- + " || " + PACKAGE + " || '/' || " + CLASS);
- return map;
- }
-
- private static void addProjection(HashMap<String, String> map, String name, String value) {
- if (!value.equals(name)) {
- value = value + " AS " + name;
- }
- map.put(name, value);
- }
-
- /**
- * Updates the cached list of installed applications.
- *
- * @param packageName Name of package whose activities to update.
- * If {@code null}, all packages are updated.
- */
- private synchronized void updateApplicationsList(String packageName) {
- if (DBG) Log.d(TAG, "Updating database (packageName = " + packageName + ")...");
-
- DatabaseUtils.InsertHelper inserter =
- new DatabaseUtils.InsertHelper(mDb, APPLICATIONS_TABLE);
- int nameCol = inserter.getColumnIndex(NAME);
- int descriptionCol = inserter.getColumnIndex(DESCRIPTION);
- int packageCol = inserter.getColumnIndex(PACKAGE);
- int classCol = inserter.getColumnIndex(CLASS);
- int iconCol = inserter.getColumnIndex(ICON);
- int launchCountCol = inserter.getColumnIndex(LAUNCH_COUNT);
- int lastResumeTimeCol = inserter.getColumnIndex(LAST_RESUME_TIME);
-
- Map<String, PkgUsageStats> usageStats = fetchUsageStats();
-
- mDb.beginTransaction();
- try {
- removeApplications(packageName);
- String description = getContext().getString(R.string.application_desc);
- // Iterate and find all the activities which have the LAUNCHER category set.
- Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- if (packageName != null) {
- // Limit to activities in the package, if given
- mainIntent.setPackage(packageName);
- }
- final PackageManager manager = getPackageManager();
- List<ResolveInfo> activities = manager.queryIntentActivities(mainIntent, 0);
- int activityCount = activities == null ? 0 : activities.size();
- for (int i = 0; i < activityCount; i++) {
- ResolveInfo info = activities.get(i);
- String title = info.loadLabel(manager).toString();
- String activityClassName = info.activityInfo.name;
- if (TextUtils.isEmpty(title)) {
- title = activityClassName;
- }
-
- String activityPackageName = info.activityInfo.applicationInfo.packageName;
- if (DBG) Log.d(TAG, "activity " + activityPackageName + "/" + activityClassName);
- PkgUsageStats stats = usageStats.get(activityPackageName);
- int launchCount = 0;
- long lastResumeTime = 0;
- if (stats != null) {
- launchCount = stats.launchCount;
- if (stats.componentResumeTimes.containsKey(activityClassName)) {
- lastResumeTime = stats.componentResumeTimes.get(activityClassName);
- }
- }
-
- String icon = getActivityIconUri(info.activityInfo);
- inserter.prepareForInsert();
- inserter.bind(nameCol, title);
- inserter.bind(descriptionCol, description);
- inserter.bind(packageCol, activityPackageName);
- inserter.bind(classCol, activityClassName);
- inserter.bind(iconCol, icon);
- inserter.bind(launchCountCol, launchCount);
- inserter.bind(lastResumeTimeCol, lastResumeTime);
- inserter.execute();
- }
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- inserter.close();
- }
-
- if (DBG) Log.d(TAG, "Finished updating database.");
- }
-
- @VisibleForTesting
- protected synchronized void updateUsageStats() {
- if (DBG) Log.d(TAG, "Update application usage stats.");
- Map<String, PkgUsageStats> usageStats = fetchUsageStats();
-
- mDb.beginTransaction();
- try {
- for (Map.Entry<String, PkgUsageStats> statsEntry : usageStats.entrySet()) {
- ContentValues updatedLaunchCount = new ContentValues();
- String packageName = statsEntry.getKey();
- PkgUsageStats stats = statsEntry.getValue();
- updatedLaunchCount.put(LAUNCH_COUNT, stats.launchCount);
-
- mDb.update(APPLICATIONS_TABLE, updatedLaunchCount,
- PACKAGE + " = ?", new String[] { packageName });
-
- for (Map.Entry<String, Long> crtEntry: stats.componentResumeTimes.entrySet()) {
- ContentValues updatedLastResumeTime = new ContentValues();
- String componentName = crtEntry.getKey();
- updatedLastResumeTime.put(LAST_RESUME_TIME, crtEntry.getValue());
-
- mDb.update(APPLICATIONS_TABLE, updatedLastResumeTime,
- PACKAGE + " = ? AND " + CLASS + " = ?",
- new String[] { packageName, componentName });
- }
- }
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
-
- if (DBG) Log.d(TAG, "Finished updating application usage stats in database.");
- }
-
- private String getActivityIconUri(ActivityInfo activityInfo) {
- int icon = activityInfo.getIconResource();
- if (icon == 0) return null;
- Uri uri = getResourceUri(activityInfo.applicationInfo, icon);
- return uri == null ? null : uri.toString();
- }
-
- private void removeApplications(String packageName) {
- if (packageName == null) {
- mDb.delete(APPLICATIONS_TABLE, null, null);
- } else {
- mDb.delete(APPLICATIONS_TABLE, PACKAGE + " = ?", new String[] { packageName });
- }
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- private Uri getResourceUri(ApplicationInfo appInfo, int res) {
- try {
- Resources resources = getPackageManager().getResourcesForApplication(appInfo);
- return getResourceUri(resources, appInfo.packageName, res);
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- } catch (Resources.NotFoundException e) {
- return null;
- }
- }
-
- private static Uri getResourceUri(Resources resources, String appPkg, int res)
- throws Resources.NotFoundException {
- String resPkg = resources.getResourcePackageName(res);
- String type = resources.getResourceTypeName(res);
- String name = resources.getResourceEntryName(res);
- return makeResourceUri(appPkg, resPkg, type, name);
- }
-
- private static Uri makeResourceUri(String appPkg, String resPkg, String type, String name)
- throws Resources.NotFoundException {
- Uri.Builder uriBuilder = new Uri.Builder();
- uriBuilder.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE);
- uriBuilder.encodedAuthority(appPkg);
- uriBuilder.appendEncodedPath(type);
- if (!appPkg.equals(resPkg)) {
- uriBuilder.appendEncodedPath(resPkg + ":" + name);
- } else {
- uriBuilder.appendEncodedPath(name);
- }
- return uriBuilder.build();
- }
-
- @VisibleForTesting
- protected Map<String, PkgUsageStats> fetchUsageStats() {
- try {
- ActivityManager activityManager = (ActivityManager)
- getContext().getSystemService(Context.ACTIVITY_SERVICE);
-
- if (activityManager != null) {
- Map<String, PkgUsageStats> stats = new HashMap<String, PkgUsageStats>();
- PkgUsageStats[] pkgUsageStats = activityManager.getAllPackageUsageStats();
- if (pkgUsageStats != null) {
- for (PkgUsageStats pus : pkgUsageStats) {
- stats.put(pus.packageName, pus);
- }
- }
- return stats;
- }
- } catch (Exception e) {
- Log.w(TAG, "Could not fetch usage stats", e);
- }
- return new HashMap<String, PkgUsageStats>();
- }
-
- @VisibleForTesting
- protected PackageManager getPackageManager() {
- return getContext().getPackageManager();
- }
-
- @VisibleForTesting
- protected boolean hasGlobalSearchPermission() {
- // Only the global-search system is allowed to see the usage stats of
- // applications. Without this restriction the ApplicationsProvider
- // could leak information about the user's behavior to applications.
- return (PackageManager.PERMISSION_GRANTED ==
- getContext().checkCallingPermission(android.Manifest.permission.GLOBAL_SEARCH));
- }
-}