Retrieving Application Launch Statistics and Usage Data on Android
The com.android.internal.os.PkgUsageStats class provides access to application launch counts and runtime statistics. Since this class is not part of the public SDK, direct usage requires either source-level access or reflection techniques.
For native Android development, the following approach demonstrates how to retrieve usage data:
import com.android.internal.app.IUsageStats;
import com.android.internal.os.PkgUsageStats;
public int compare(ApplicationInfo firstApp, ApplicationInfo secondApp) {
ComponentName firstComponent = firstApp.intent.getComponent();
ComponentName secondComponent = secondApp.intent.getComponent();
int comparisonResult = 0;
IUsageStats usageService = IUsageStats.Stub.asInterface(
ServiceManager.getService("usagestats"));
try {
PkgUsageStats firstStats = usageService.getPkgUsageStats(firstComponent);
PkgUsageStats secondStats = usageService.getPkgUsageStats(secondComponent);
if (firstStats != null && secondStats != null) {
if ((firstStats.launchCount > secondStats.launchCount) ||
((firstStats.launchCount == secondStats.launchCount) &&
(firstStats.usageTime > secondStats.usageTime))) {
comparisonResult = -1;
} else if ((firstStats.launchCount < secondStats.launchCount) ||
((firstStats.launchCount == secondStats.launchCount) &&
(firstStats.usageTime < secondStats.usageTime))) {
comparisonResult = 1;
} else {
comparisonResult = 0;
}
} else if (firstStats != null && secondStats == null) {
comparisonResult = -1;
} else if (firstStats == null && secondStats != null) {
comparisonResult = 1;
}
} catch (RemoteException e) {
Log.i("TAG", "Failed to retrieve usage statistics");
}
return comparisonResult;
}
When working within the SDK environment, reflection can be used to access these internal APIs:
public int compare(ApplicationInfo firstApp, ApplicationInfo secondApp) {
ComponentName firstComponent = firstApp.intent.getComponent();
ComponentName secondComponent = secondApp.intent.getComponent();
int firstLaunchCount, secondLaunchCount;
long firstUsageTime, secondUsageTime;
int comparisonResult = 0;
try {
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getService = serviceManager.getMethod("getService", String.class);
Object remoteService = getService.invoke(null, "usagestats");
Class<?> stubClass = Class.forName("com.android.internal.app.IUsageStats$Stub");
Method asInterface = stubClass.getMethod("asInterface", IBinder.class);
Object usageStatsInterface = asInterface.invoke(null, remoteService);
Method getPkgUsageStats = usageStatsInterface.getClass().getMethod(
"getPkgUsageStats", ComponentName.class);
Object firstStats = getPkgUsageStats.invoke(usageStatsInterface, firstComponent);
Object secondStats = getPkgUsageStats.invoke(usageStatsInterface, secondComponent);
Class<?> pkgStatsClass = Class.forName("com.android.internal.os.PkgUsageStats");
firstLaunchCount = pkgStatsClass.getDeclaredField("launchCount").getInt(firstStats);
secondLaunchCount = pkgStatsClass.getDeclaredField("launchCount").getInt(secondStats);
firstUsageTime = pkgStatsClass.getDeclaredField("usageTime").getLong(firstStats);
secondUsageTime = pkgStatsClass.getDeclaredField("usageTime").getLong(secondStats);
if ((firstLaunchCount > secondLaunchCount) ||
((firstLaunchCount == secondLaunchCount) && (firstUsageTime > secondUsageTime))) {
comparisonResult = 1;
} else if ((firstLaunchCount < secondLaunchCount) ||
((firstLaunchCount == secondLaunchCount) && (firstUsageTime < secondUsageTime))) {
comparisonResult = -1;
} else {
comparisonResult = 0;
}
} catch (Exception e) {
Log.e("###", e.toString(), e);
}
return comparisonResult;
}
For end users seeking their own device usage analytics, Android provides built-in tools through engineering mode. On devices running Android 4.0, enter the dialer and input "##4636##" to access diagnostic menus. Within the menu, select "Usage statistics" to view application usage metrics including launch frequency and time spent.