summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Visontay <pvisontay@google.com>2011-02-11 18:36:18 +0000
committerPeter Visontay <pvisontay@google.com>2011-02-25 12:03:19 +0000
commit7089c89c9ec21f28326ac6a9e9e91344749a02e0 (patch)
tree205f615b265a66bf30933bc14afc3265c93264bb
parentd995cd1f165074ebf14b9b884486770f2c219499 (diff)
downloadApplicationsProvider-7089c89c9ec21f28326ac6a9e9e91344749a02e0.tar.gz
Made ApplicationsProvider fetch launch counts from a remote service.
Bug: 3431684 Change-Id: Ie350ef440a7a49e5fdae5723414bfbab11f09793
-rw-r--r--AndroidManifest.xml7
-rw-r--r--res/values/strings.xml7
-rw-r--r--src/com/android/providers/applications/ApplicationLauncher.java17
-rw-r--r--src/com/android/providers/applications/ApplicationsProvider.java187
-rw-r--r--src/com/android/providers/applications/PersistentDb.java187
-rw-r--r--tests/runtests1
-rw-r--r--tests/src/com/android/providers/applications/ApplicationsProviderForTesting.java16
-rw-r--r--tests/src/com/android/providers/applications/ApplicationsProviderTest.java98
-rw-r--r--tests/src/com/android/providers/applications/MockActivityManager.java36
9 files changed, 182 insertions, 374 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3cdaaa9..4e4bfa2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2,12 +2,7 @@
package="com.android.providers.applications"
android:sharedUserId="android.uid.shared">
- <!-- Allows the system to register app launches so the
- ApplicationsProvider can also rank apps by frequency of use. -->
- <permission android:name="com.google.android.providers.applications.permission.INCREASE_LAUNCH_COUNT"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_increase_launch_count"
- android:description="@string/permdesc_increase_launch_count" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<application android:process="android.process.acore" android:label="@string/app_label">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6974f2c..2c296ef 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -28,11 +28,4 @@
settings. -->
<string name="settings_description">Names of installed applications</string>
- <!-- Label for permission to increase an app's launch count. -->
- <string name="permlab_increase_launch_count">modify application launch counts</string>
-
- <!-- Description of permission to increase an app's launch count. -->
- <string name="permdesc_increase_launch_count">Allows a launcher to
- increase the launch count of applications (used for ranking apps).</string>
-
</resources>
diff --git a/src/com/android/providers/applications/ApplicationLauncher.java b/src/com/android/providers/applications/ApplicationLauncher.java
index 343c855..0b38dfe 100644
--- a/src/com/android/providers/applications/ApplicationLauncher.java
+++ b/src/com/android/providers/applications/ApplicationLauncher.java
@@ -23,7 +23,6 @@ import android.content.ComponentName;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Applications;
import android.util.Log;
@@ -99,22 +98,6 @@ public class ApplicationLauncher extends ListActivity {
} catch (ActivityNotFoundException ex) {
Log.w(TAG, "Activity not found: " + componentName);
}
-
- increaseLaunchCount(componentName);
}
}
-
- private void increaseLaunchCount(final ComponentName componentName) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... args) {
- try {
- Applications.increaseLaunchCount(getContentResolver(), componentName);
- } catch (RuntimeException e) {
- Log.w(TAG, "Could not increase launch count", e);
- }
- return null;
- }
- }.execute();
- }
}
diff --git a/src/com/android/providers/applications/ApplicationsProvider.java b/src/com/android/providers/applications/ApplicationsProvider.java
index fbca4cb..e46aa52 100644
--- a/src/com/android/providers/applications/ApplicationsProvider.java
+++ b/src/com/android/providers/applications/ApplicationsProvider.java
@@ -18,6 +18,9 @@ package com.android.providers.applications;
import com.android.internal.content.PackageMonitor;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -74,7 +77,6 @@ public class ApplicationsProvider extends ContentProvider {
private static final int SEARCH_SUGGEST = 0;
private static final int SHORTCUT_REFRESH = 1;
private static final int SEARCH = 2;
- private static final int LAUNCH_COUNT_INCREASE = 3;
private static final UriMatcher sURIMatcher = buildUriMatcher();
@@ -82,6 +84,11 @@ public class ApplicationsProvider extends ContentProvider {
// Messages for mHandler
private static final int MSG_UPDATE_ALL = 0;
+ private static final int MSG_UPDATE_APP_LAUNCH_COUNTS = 1;
+
+ // A request to update application launch counts.
+ private static final String INTENT_UPDATE_LAUNCH_COUNTS =
+ ApplicationsProvider.class.getName() + ".UPDATE_LAUNCH_COUNTS";
public static final String _ID = "_id";
public static final String NAME = "name";
@@ -97,12 +104,6 @@ public class ApplicationsProvider extends ContentProvider {
"applicationsLookup JOIN " + APPLICATIONS_TABLE + " ON"
+ " applicationsLookup.source = " + APPLICATIONS_TABLE + "." + _ID;
- private static final String INCREASE_LAUNCH_COUNT_SQL =
- "UPDATE " + APPLICATIONS_TABLE +
- " SET " + LAUNCH_COUNT + " = " + LAUNCH_COUNT + " + 1" +
- " WHERE " + PACKAGE + " = ?" +
- " AND " + CLASS + " = ?";
-
private static final HashMap<String, String> sSearchSuggestionsProjectionMap =
buildSuggestionsProjectionMap();
private static final HashMap<String, String> sSearchProjectionMap =
@@ -111,13 +112,9 @@ public class ApplicationsProvider extends ContentProvider {
/**
* An in-memory database storing the details of applications installed on
* the device. Populated when the ApplicationsProvider is launched.
- *
- * @see PersistentDb
*/
private SQLiteDatabase mDb;
- private PersistentDb mPersistentDb;
-
// Handler that runs DB updates.
private Handler mHandler;
@@ -129,6 +126,11 @@ public class ApplicationsProvider extends ContentProvider {
*/
private static final long UPDATE_DELAY_MILLIS = 1000L;
+ /**
+ * Application launch counts will be updated every 6 hours.
+ */
+ private static final long LAUNCH_COUNT_UPDATE_INTERVAL = AlarmManager.INTERVAL_HOUR * 6;
+
private static UriMatcher buildUriMatcher() {
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI(Applications.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
@@ -143,8 +145,6 @@ public class ApplicationsProvider extends ContentProvider {
SEARCH);
matcher.addURI(Applications.AUTHORITY, Applications.SEARCH_PATH + "/*",
SEARCH);
- matcher.addURI(Applications.AUTHORITY, Applications.INCREASE_LAUNCH_COUNT_PATH,
- LAUNCH_COUNT_INCREASE);
return matcher;
}
@@ -172,10 +172,23 @@ public class ApplicationsProvider extends ContentProvider {
}
};
+ // Broadcast receiver receiving "update application launch counts" requests
+ // fired by the AlarmManager at regular intervals.
+ private BroadcastReceiver mLaunchCountUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (INTENT_UPDATE_LAUNCH_COUNTS.equals(action)) {
+ if (DBG) Log.d(TAG, "Launch count update requested");
+ mHandler.removeMessages(MSG_UPDATE_APP_LAUNCH_COUNTS);
+ Message.obtain(mHandler, MSG_UPDATE_APP_LAUNCH_COUNTS).sendToTarget();
+ }
+ }
+ };
+
@Override
public boolean onCreate() {
createDatabase();
- createPersistentDatabase();
// Listen for package changes
new MyPackageMonitor().register(getContext(), true);
// Listen for locale changes
@@ -187,6 +200,7 @@ public class ApplicationsProvider extends ContentProvider {
mHandler = new UpdateHandler(thread.getLooper());
// Kick off first apps update
postUpdateAll();
+ scheduleRegularLaunchCountUpdates();
return true;
}
@@ -202,6 +216,9 @@ public class ApplicationsProvider extends ContentProvider {
case MSG_UPDATE_ALL:
updateApplicationsList(null);
break;
+ case MSG_UPDATE_APP_LAUNCH_COUNTS:
+ updateLaunchCounts();
+ break;
default:
Log.e(TAG, "Unknown message: " + msg.what);
break;
@@ -221,6 +238,27 @@ public class ApplicationsProvider extends ContentProvider {
mHandler.sendMessageDelayed(msg, UPDATE_DELAY_MILLIS);
}
+ @VisibleForTesting
+ protected void scheduleRegularLaunchCountUpdates() {
+ // Set up a recurring event that sends an intent caught by the
+ // mLaunchCountUpdateReceiver event handler. This event handler
+ // will update application launch counts in the ApplicationsProvider's
+ // database.
+ getContext().registerReceiver(
+ mLaunchCountUpdateReceiver,
+ new IntentFilter(INTENT_UPDATE_LAUNCH_COUNTS));
+
+ PendingIntent updateLaunchCountsIntent = PendingIntent.getBroadcast(
+ getContext(), 0, new Intent(INTENT_UPDATE_LAUNCH_COUNTS),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+
+ // Schedule the recurring event.
+ AlarmManager alarmManager =
+ (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, LAUNCH_COUNT_UPDATE_INTERVAL,
+ LAUNCH_COUNT_UPDATE_INTERVAL, updateLaunchCountsIntent);
+ }
+
// ----------
// END ASYC UPDATE CODE
// ----------
@@ -273,15 +311,6 @@ public class ApplicationsProvider extends ContentProvider {
}
/**
- * Creates a persistent database that complements the in-memory one by
- * storing values that must be kept even if the ApplicationsProvider is
- * restarted.
- */
- private void createPersistentDatabase() {
- mPersistentDb = new PersistentDb(getContext());
- }
-
- /**
* This will always return {@link SearchManager#SUGGEST_MIME_TYPE} as this
* provider is purely to provide suggestions.
*/
@@ -474,10 +503,7 @@ public class ApplicationsProvider extends ContentProvider {
int iconCol = inserter.getColumnIndex(ICON);
int launchCountCol = inserter.getColumnIndex(LAUNCH_COUNT);
- // We'll copy the values stored in the persistent DB to the in-memory
- // one to improve querying speed.
- Map<ComponentName, Long> launchCounts = mPersistentDb.getLaunchCounts();
- List<ComponentName> newComponents = new ArrayList<ComponentName>();
+ Map<String, Integer> launchCounts = fetchLaunchCounts();
mDb.beginTransaction();
try {
@@ -502,12 +528,9 @@ public class ApplicationsProvider extends ContentProvider {
}
String activityPackageName = info.activityInfo.applicationInfo.packageName;
- ComponentName componentName = new ComponentName(activityPackageName, activityClassName);
- Long launchCount = launchCounts.get(componentName);
+ Integer launchCount = launchCounts.get(activityPackageName);
if (launchCount == null) {
- // Component not in the persisted DB yet.
- newComponents.add(componentName);
- launchCount = 0L;
+ launchCount = 0;
}
String icon = getActivityIconUri(info.activityInfo);
@@ -526,11 +549,6 @@ public class ApplicationsProvider extends ContentProvider {
inserter.close();
}
- // Add new components to persistent DB.
- for (ComponentName newComponent : newComponents) {
- mPersistentDb.insertNewComponent(newComponent);
- }
-
if (onApplicationsListUpdated != null) {
onApplicationsListUpdated.run();
}
@@ -538,6 +556,27 @@ public class ApplicationsProvider extends ContentProvider {
if (DBG) Log.d(TAG, "Finished updating database.");
}
+ @VisibleForTesting
+ protected void updateLaunchCounts() {
+ Map<String, Integer> launchCounts = fetchLaunchCounts();
+
+ mDb.beginTransaction();
+ try {
+ for (String packageName : launchCounts.keySet()) {
+ ContentValues updatedValues = new ContentValues();
+ updatedValues.put(LAUNCH_COUNT, launchCounts.get(packageName));
+
+ mDb.update(APPLICATIONS_TABLE, updatedValues,
+ PACKAGE + " = ?", new String[] { packageName });
+ }
+ mDb.setTransactionSuccessful();
+ } finally {
+ mDb.endTransaction();
+ }
+
+ if (DBG) Log.d(TAG, "Finished updating application launch counts in database.");
+ }
+
private String getActivityIconUri(ActivityInfo activityInfo) {
int icon = activityInfo.getIconResource();
if (icon == 0) return null;
@@ -556,61 +595,7 @@ public class ApplicationsProvider extends ContentProvider {
@Override
public Uri insert(Uri uri, ContentValues values) {
- if (DBG) Log.d(TAG, "Data insert request arrived on uri "
- + uri + " with parameters: " + values);
-
- switch (sURIMatcher.match(uri)) {
- case LAUNCH_COUNT_INCREASE:
- increaseLaunchCount(values);
- return null;
-
- default:
- throw new IllegalArgumentException("URL " + uri + " doesn't support inserts.");
- }
- }
-
- private void increaseLaunchCount(ContentValues requestParameters) {
- String packageName = requestParameters.getAsString(
- Applications.INCREASE_LAUNCH_COUNT_PACKAGE);
- String className = requestParameters.getAsString(
- Applications.INCREASE_LAUNCH_COUNT_CLASS);
-
- if (TextUtils.isEmpty(packageName)) {
- Log.w(TAG, Applications.INCREASE_LAUNCH_COUNT_PACKAGE + " parameter missing");
- return;
- }
-
- if (TextUtils.isEmpty(className)) {
- Log.w(TAG, Applications.INCREASE_LAUNCH_COUNT_CLASS + " parameter missing");
- return;
- }
-
- ComponentName componentName = new ComponentName(packageName, className);
- increaseLaunchCount(componentName);
- }
-
- private void increaseLaunchCount(ComponentName componentName) {
- enforcePermissionForLaunchCountIncrease();
-
- if (DBG) Log.d(TAG, "Increasing launch count of component " + componentName);
-
- // Increase the launch count in the in-memory database.
- mDb.beginTransaction();
- try {
- mDb.execSQL(INCREASE_LAUNCH_COUNT_SQL, new Object[] {
- componentName.getPackageName(),
- componentName.getClassName()});
-
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
-
- // Also persist the new value since the ApplicationsProvider may be
- // killed unexpectedly.
- mPersistentDb.increaseLaunchCount(componentName);
-
- if (DBG) Log.d(TAG, "Launch count increased for component " + componentName);
+ throw new UnsupportedOperationException();
}
@Override
@@ -658,14 +643,22 @@ public class ApplicationsProvider extends ContentProvider {
}
@VisibleForTesting
- protected PackageManager getPackageManager() {
- return getContext().getPackageManager();
+ protected Map<String, Integer> fetchLaunchCounts() {
+ try {
+ ActivityManager activityManager = (ActivityManager)
+ getContext().getSystemService(Context.ACTIVITY_SERVICE);
+
+ Map<String, Integer> allPackageLaunchCounts = activityManager.getAllPackageLaunchCounts();
+ return allPackageLaunchCounts;
+ } catch (Exception e) {
+ Log.w(TAG, "Could not fetch launch counts", e);
+ return new HashMap<String, Integer>();
+ }
}
@VisibleForTesting
- protected void enforcePermissionForLaunchCountIncrease() {
- getContext().enforceCallingOrSelfPermission(
- Manifest.permission.INCREASE_LAUNCH_COUNT, null);
+ protected PackageManager getPackageManager() {
+ return getContext().getPackageManager();
}
@VisibleForTesting
diff --git a/src/com/android/providers/applications/PersistentDb.java b/src/com/android/providers/applications/PersistentDb.java
deleted file mode 100644
index 3394369..0000000
--- a/src/com/android/providers/applications/PersistentDb.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.providers.applications;
-
-import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Manages a database that stores those details of applications that are
- * managed by the ApplicationsProvider. As these properties are not retrievable
- * from an external service and therefore have to be stored in a persistent
- * database.
- *
- * Currently used to store the launch counts of applications to improve ranking
- * by popularity.
- */
-class PersistentDb {
-
- private static final boolean DBG = false;
-
- private static final String TAG = "ApplicationsProvider";
-
- private static final int DB_VERSION = 1;
-
- // Table names and constants.
- private static final String APPLICATIONS_TABLE = "applications";
- public static final String PACKAGE = "package";
- public static final String CLASS = "class";
- public static final String LAUNCH_COUNT = "launch_count";
-
- private static final String INCREASE_LAUNCH_COUNT_SQL =
- "UPDATE " + APPLICATIONS_TABLE +
- " SET " + LAUNCH_COUNT + " = " + LAUNCH_COUNT + " + 1" +
- " WHERE " + PACKAGE + " = ?" +
- " AND " + CLASS + " = ?";
-
- private SQLiteDatabase mDb;
-
- public PersistentDb(Context context) {
- openDatabase(context);
- }
-
- private void openDatabase(Context context) {
- try {
- mDb = new DbOpenHelper(context, DB_VERSION).getWritableDatabase();
- if (DBG) Log.d(TAG, "Opened persistent ApplicationsProvider database");
- } catch (SQLiteException e) {
- Log.w(TAG, "Could not open persistent ApplicationsProvider database", e);
- }
- }
-
- /**
- * Returns the persisted launch count of each component.
- */
- Map<ComponentName, Long> getLaunchCounts() {
- Cursor cursor = null;
- try {
- cursor = mDb.query(
- APPLICATIONS_TABLE,
- new String[] { PACKAGE, CLASS, LAUNCH_COUNT },
- null, null, null, null, null);
- } catch (SQLiteException e) {
- Log.w(TAG, "Could not query persistent database.", e);
- return new HashMap<ComponentName, Long>();
- }
-
- try {
- int packageCol = cursor.getColumnIndex(PACKAGE);
- int classCol = cursor.getColumnIndex(CLASS);
- int launchCountCol = cursor.getColumnIndex(LAUNCH_COUNT);
-
- HashMap<ComponentName, Long> packageLaunchCounts = new HashMap<ComponentName, Long>();
- while (cursor.moveToNext()) {
- ComponentName componentName = new ComponentName(
- cursor.getString(packageCol),
- cursor.getString(classCol));
-
- packageLaunchCounts.put(
- componentName,
- cursor.getLong(launchCountCol));
- }
- return packageLaunchCounts;
- } finally {
- if (cursor != null && !cursor.isClosed()) {
- cursor.close();
- }
- }
- }
-
- /**
- * Add a new component to the database with a zero launch count.
- */
- void insertNewComponent(ComponentName component) {
- if (DBG) Log.d(TAG, "Adding component " + component + " to persistent database.");
- try {
- mDb.beginTransaction();
- try {
- ContentValues columns = new ContentValues();
- columns.put(PACKAGE, component.getPackageName());
- columns.put(CLASS, component.getClassName());
- columns.put(LAUNCH_COUNT, 0);
-
- mDb.insert(APPLICATIONS_TABLE, null, columns);
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
- } catch (SQLiteException e) {
- Log.w(TAG, "Could not add component " + component + " to persistent database.", e);
- }
- }
-
- /**
- * Increase the launch count of a single package.
- */
- void increaseLaunchCount(ComponentName componentName) {
- try {
- mDb.beginTransaction();
- try {
- mDb.execSQL(INCREASE_LAUNCH_COUNT_SQL, new Object[] {
- componentName.getPackageName(),
- componentName.getClassName()});
-
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
- } catch (SQLiteException e) {
- Log.w(TAG, "Could not increase persisted launch count of " + componentName, e);
- }
- }
-
- private class DbOpenHelper extends SQLiteOpenHelper {
-
- private static final String DB_NAME = "applicationsprovider.db";
-
- public DbOpenHelper(Context context, int version) {
- super(context, DB_NAME, null, version);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- throw new UnsupportedOperationException("ApplicationsProvider DB cannot"
- + " require an upgrade - only one version exists so far.");
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- if (DBG) Log.d(TAG, "Creating persistent database for ApplicationsProvider.");
-
- db.execSQL("CREATE TABLE " + APPLICATIONS_TABLE + " (" +
- PACKAGE + " TEXT, " +
- CLASS + " TEXT, " +
- LAUNCH_COUNT + " INTEGER DEFAULT 0" +
- ");");
-
- db.execSQL("CREATE INDEX componentNameIndex ON " + APPLICATIONS_TABLE + " ("
- + PACKAGE + ","
- + CLASS
- + ");");
- }
- }
-}
diff --git a/tests/runtests b/tests/runtests
index 184a278..be1c779 100644
--- a/tests/runtests
+++ b/tests/runtests
@@ -1,4 +1,5 @@
mmm packages/providers/ApplicationsProvider || return
+mmm packages/providers/ApplicationsProvider/tests || return
adb install -r ${OUT}/system/app/ApplicationsProvider.apk || return
adb install -r ${OUT}/data/app/ApplicationsProviderTests.apk || return
adb shell am instrument -w -e class com.android.providers.applications.ApplicationsProviderTest com.android.providers.applications.tests/android.test.InstrumentationTestRunner || return
diff --git a/tests/src/com/android/providers/applications/ApplicationsProviderForTesting.java b/tests/src/com/android/providers/applications/ApplicationsProviderForTesting.java
index ea91fd0..fa8645c 100644
--- a/tests/src/com/android/providers/applications/ApplicationsProviderForTesting.java
+++ b/tests/src/com/android/providers/applications/ApplicationsProviderForTesting.java
@@ -18,6 +18,8 @@ package com.android.providers.applications;
import android.content.pm.PackageManager;
+import java.util.Map;
+
/**
* An extension of {@link ApplicationsProvider} that makes its testing easier.
*/
@@ -25,6 +27,8 @@ public class ApplicationsProviderForTesting extends ApplicationsProvider {
private PackageManager mMockPackageManager;
+ private MockActivityManager mMockActivityManager;
+
private boolean mCanRankByLaunchCount;
@Override
@@ -37,8 +41,12 @@ public class ApplicationsProviderForTesting extends ApplicationsProvider {
}
@Override
- protected void enforcePermissionForLaunchCountIncrease() {
- // Tests are allowed to do this.
+ protected Map<String, Integer> fetchLaunchCounts() {
+ return mMockActivityManager.getAllPackageLaunchCounts();
+ }
+
+ protected void setMockActivityManager(MockActivityManager mockActivityManager) {
+ mMockActivityManager = mockActivityManager;
}
protected void setCanRankByLaunchCount(boolean canRankByLaunchCount) {
@@ -49,4 +57,8 @@ public class ApplicationsProviderForTesting extends ApplicationsProvider {
protected boolean canRankByLaunchCount() {
return mCanRankByLaunchCount;
}
+
+ @Override
+ protected void scheduleRegularLaunchCountUpdates() {
+ }
}
diff --git a/tests/src/com/android/providers/applications/ApplicationsProviderTest.java b/tests/src/com/android/providers/applications/ApplicationsProviderTest.java
index 9d07bb2..77bc064 100644
--- a/tests/src/com/android/providers/applications/ApplicationsProviderTest.java
+++ b/tests/src/com/android/providers/applications/ApplicationsProviderTest.java
@@ -17,17 +17,13 @@
package com.android.providers.applications;
import android.content.ComponentName;
-import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
-import android.net.Uri;
import android.provider.Applications;
import android.test.ProviderTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
/**
@@ -43,6 +39,8 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
private ApplicationsProviderForTesting mProvider;
+ private MockActivityManager mMockActivityManager;
+
public ApplicationsProviderTest() {
super(ApplicationsProviderForTesting.class, Applications.AUTHORITY);
}
@@ -51,6 +49,7 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
protected void setUp() throws Exception {
super.setUp();
mProvider = getProvider();
+ mMockActivityManager = new MockActivityManager();
initProvider(mProvider);
}
@@ -62,6 +61,7 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
MockPackageManager mockPackageManager = new MockPackageManager();
addDefaultTestPackages(mockPackageManager);
provider.setMockPackageManager(mockPackageManager);
+ provider.setMockActivityManager(mMockActivityManager);
// We need to wait for the applications database to be updated (it's
// updated with a slight delay by a separate thread) before we can use
@@ -118,14 +118,37 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
"Ebay", "Email", "Fakeapp");
}
- public void testSearch_appsAreRankedByLaunchCount() {
+ public void testSearch_appsAreRankedByLaunchCountOnStartup() throws Exception {
+ mMockActivityManager.addLaunchCount("d", 3);
+ mMockActivityManager.addLaunchCount("b", 1);
+ // Missing launch count for "a".
+ mMockActivityManager.addLaunchCount("c", 0);
+
+ // Launch count database is populated on startup.
+ mProvider = createNewProvider(getMockContext());
+ mProvider.setCanRankByLaunchCount(true);
+ initProvider(mProvider);
+
+ // Override the previous provider with the new instance in the
+ // ContentResolver.
+ getMockContentResolver().addProvider(Applications.AUTHORITY, mProvider);
+
+ // New ranking: D, B, A, C (first by launch count, then
+ // - if the launch counts of two apps are equal - alphabetically)
+ testSearch("alphabetic", "AlphabeticD", "AlphabeticB", "AlphabeticA", "AlphabeticC");
+ }
+
+ public void testSearch_appsAreRankedByLaunchCountAfterScheduledUpdate() {
mProvider.setCanRankByLaunchCount(true);
- // Original ranking: A, B, C, D (alphabetic; all launch counts are 0
- // by default).
- increaseLaunchCount(new ComponentName("b", "b.BView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
+ mMockActivityManager.addLaunchCount("d", 3);
+ mMockActivityManager.addLaunchCount("b", 1);
+ // Missing launch count for "a".
+ mMockActivityManager.addLaunchCount("c", 0);
+
+ // Fetch new data from launch count provider (in the real instance this
+ // is scheduled).
+ mProvider.updateLaunchCounts();
// New ranking: D, B, A, C (first by launch count, then
// - if the launch counts of two apps are equal - alphabetically)
@@ -141,52 +164,19 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
// Simulate non-privileged calling application.
mProvider.setCanRankByLaunchCount(false);
- // Original ranking: A, B, C, D (alphabetic; all launch counts are 0
- // by default).
- increaseLaunchCount(new ComponentName("b", "b.BView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
+ mMockActivityManager.addLaunchCount("d", 3);
+ mMockActivityManager.addLaunchCount("b", 1);
+ mMockActivityManager.addLaunchCount("a", 0);
+ mMockActivityManager.addLaunchCount("c", 0);
+
+ // Fetch new data from launch count provider.
+ mProvider.updateLaunchCounts();
// Launch count information mustn't be leaked - ranking is still
// alphabetic.
testSearch("alphabetic", "AlphabeticA", "AlphabeticB", "AlphabeticC", "AlphabeticD");
}
- /**
- * Tests that the launch count values are persisted even if the
- * ApplicationsProvider is restarted.
- */
- public void testSearch_launchCountInformationIsPersistent() throws Exception {
- mProvider.setCanRankByLaunchCount(true);
-
- // Original ranking: A, B, C, D (alphabetic; all launch counts are 0
- // by default).
- increaseLaunchCount(new ComponentName("b", "b.BView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
- increaseLaunchCount(new ComponentName("d", "d.DView"));
-
- // New ranking: D, B, A, C (first by launch count, then
- // - if the launch counts of two apps are equal - alphabetically)
- testSearch("alphabetic", "AlphabeticD", "AlphabeticB", "AlphabeticA", "AlphabeticC");
-
- // Now we'll create a new ApplicationsProvider instance (the provider
- // may be killed by Android at any time) and verify that it has access
- // to the same launch count information as the original provider instance.
- // The new instance will use the same IsolatedContext as the previous one.
- ApplicationsProviderForTesting newProviderInstance = createNewProvider(mProvider.getContext());
- newProviderInstance.setCanRankByLaunchCount(true);
- assertNotSame(newProviderInstance, mProvider);
-
- // Override the previous provider with the new instance in the
- // ContentResolver.
- getMockContentResolver().addProvider(Applications.AUTHORITY, newProviderInstance);
-
- initProvider(newProviderInstance);
-
- // Verify that the launch-count-dependent ordering is still correct.
- testSearch("alphabetic", "AlphabeticD", "AlphabeticB", "AlphabeticA", "AlphabeticC");
- }
-
private void testSearch(String searchQuery, String... expectedResultsInOrder) {
Cursor cursor = Applications.search(getMockContentResolver(), searchQuery);
@@ -215,14 +205,6 @@ public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProv
}
}
- /**
- * Makes the ApplicationsProvider increase the launch count of this
- * application stored in its database.
- */
- private void increaseLaunchCount(ComponentName componentName) {
- Applications.increaseLaunchCount(getMockContentResolver(), componentName);
- }
-
private ApplicationsProviderForTesting createNewProvider(Context context) throws Exception {
ApplicationsProviderForTesting newProviderInstance =
ApplicationsProviderForTesting.class.newInstance();
diff --git a/tests/src/com/android/providers/applications/MockActivityManager.java b/tests/src/com/android/providers/applications/MockActivityManager.java
new file mode 100644
index 0000000..63deacf
--- /dev/null
+++ b/tests/src/com/android/providers/applications/MockActivityManager.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 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 java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The real ActivityManager is difficult to mock out (has a package visibility
+ * constructor), so this doesn't extend it.
+ */
+public class MockActivityManager {
+
+ private Map<String, Integer> mPackageLaunchCounts = new HashMap<String, Integer>();
+
+ public void addLaunchCount(String packageName, int launchCount) {
+ mPackageLaunchCounts.put(packageName, launchCount);
+ }
+
+ public Map<String, Integer> getAllPackageLaunchCounts() {
+ return mPackageLaunchCounts;
+ }
+}