How to Get The Time Spent on an Application in Android Programmatically

How to Get the Time spent on an application in Android Programmatically

Apps with usage access settings

Activity Classes :-

package com.example.android.appusagestatistics;

import android.app.Activity;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

/**
* Activity to display package usage statistics.
*/
public class UsageStatsActivity extends Activity implements OnItemSelectedListener {
private static final String TAG = "UsageStatsActivity";
private static final boolean localLOGV = false;
private UsageStatsManager mUsageStatsManager;
private LayoutInflater mInflater;
private UsageStatsAdapter mAdapter;
private PackageManager mPm;

public static class AppNameComparator implements Comparator<UsageStats> {
private Map<String, String> mAppLabelList;

AppNameComparator(Map<String, String> appList) {
mAppLabelList = appList;
}

@Override
public final int compare(UsageStats a, UsageStats b) {
String alabel = mAppLabelList.get(a.getPackageName());
String blabel = mAppLabelList.get(b.getPackageName());
return alabel.compareTo(blabel);
}
}

public static class LastTimeUsedComparator implements Comparator<UsageStats> {
@Override
public final int compare(UsageStats a, UsageStats b) {
// return by descending order
return (int)(b.getLastTimeUsed() - a.getLastTimeUsed());
}
}

public static class UsageTimeComparator implements Comparator<UsageStats> {
@Override
public final int compare(UsageStats a, UsageStats b) {
return (int)(b.getTotalTimeInForeground() - a.getTotalTimeInForeground());
}
}

// View Holder used when displaying views
static class AppViewHolder {
TextView pkgName;
TextView lastTimeUsed;
TextView usageTime;
}

class UsageStatsAdapter extends BaseAdapter {
// Constants defining order for display order
private static final int _DISPLAY_ORDER_USAGE_TIME = 0;
private static final int _DISPLAY_ORDER_LAST_TIME_USED = 1;
private static final int _DISPLAY_ORDER_APP_NAME = 2;

private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME;
private LastTimeUsedComparator mLastTimeUsedComparator = new LastTimeUsedComparator();
private UsageTimeComparator mUsageTimeComparator = new UsageTimeComparator();
private AppNameComparator mAppLabelComparator;
private final ArrayMap<String, String> mAppLabelMap = new ArrayMap<>();
private final ArrayList<UsageStats> mPackageStats = new ArrayList<>();

UsageStatsAdapter() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -5);

final List<UsageStats> stats =
mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST,
cal.getTimeInMillis(), System.currentTimeMillis());
if (stats == null) {
return;
}

ArrayMap<String, UsageStats> map = new ArrayMap<>();
final int statCount = stats.size();
for (int i = 0; i < statCount; i++) {
final android.app.usage.UsageStats pkgStats = stats.get(i);

// load application labels for each application
try {
ApplicationInfo appInfo = mPm.getApplicationInfo(pkgStats.getPackageName(), 0);
String label = appInfo.loadLabel(mPm).toString();
mAppLabelMap.put(pkgStats.getPackageName(), label);

UsageStats existingStats =
map.get(pkgStats.getPackageName());
if (existingStats == null) {
map.put(pkgStats.getPackageName(), pkgStats);
} else {
existingStats.add(pkgStats);
}

} catch (NameNotFoundException e) {
// This package may be gone.
}
}
mPackageStats.addAll(map.values());

// Sort list
mAppLabelComparator = new AppNameComparator(mAppLabelMap);
sortList();
}

@Override
public int getCount() {
return mPackageStats.size();
}

@Override
public Object getItem(int position) {
return mPackageStats.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
AppViewHolder holder;

// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(R.layout.usage_stats_item, null);

// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new AppViewHolder();
holder.pkgName = (TextView) convertView.findViewById(R.id.package_name);
holder.lastTimeUsed = (TextView) convertView.findViewById(R.id.last_time_used);
holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (AppViewHolder) convertView.getTag();
}

// Bind the data efficiently with the holder
UsageStats pkgStats = mPackageStats.get(position);
if (pkgStats != null) {
String label = mAppLabelMap.get(pkgStats.getPackageName());
holder.pkgName.setText(label);
holder.lastTimeUsed.setText(DateUtils.formatSameDayTime(pkgStats.getLastTimeUsed(),
System.currentTimeMillis(), DateFormat.MEDIUM, DateFormat.MEDIUM));
holder.usageTime.setText(
DateUtils.formatElapsedTime(pkgStats.getTotalTimeInForeground() / 1000));
} else {
Log.w(TAG, "No usage stats info for package:" + position);
}
return convertView;
}

void sortList(int sortOrder) {
if (mDisplayOrder == sortOrder) {
// do nothing
return;
}
mDisplayOrder= sortOrder;
sortList();
}
private void sortList() {
if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) {
if (localLOGV) Log.i(TAG, "Sorting by usage time");
Collections.sort(mPackageStats, mUsageTimeComparator);
} else if (mDisplayOrder == _DISPLAY_ORDER_LAST_TIME_USED) {
if (localLOGV) Log.i(TAG, "Sorting by last time used");
Collections.sort(mPackageStats, mLastTimeUsedComparator);
} else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) {
if (localLOGV) Log.i(TAG, "Sorting by application name");
Collections.sort(mPackageStats, mAppLabelComparator);
}
notifyDataSetChanged();
}
}

/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.usage_stats);

mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPm = getPackageManager();

Spinner typeSpinner = (Spinner) findViewById(R.id.typeSpinner);
typeSpinner.setOnItemSelectedListener(this);

ListView listView = (ListView) findViewById(R.id.pkg_list);
mAdapter = new UsageStatsAdapter();
listView.setAdapter(mAdapter);
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mAdapter.sortList(position);
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
// do nothing
}
}

Layout :-

1. usage_stats.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:text="@string/display_order_text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Spinner
android:id="@+id/typeSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/usage_stats_display_order_types" />

<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text="@string/app_name_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:paddingEnd="6dip"
android:layout_height="wrap_content" />
<TextView
android:text="@string/last_time_used_label"
android:paddingEnd="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@string/usage_time_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<ListView android:id="@+id/pkg_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false" />
</LinearLayout>

2. usage_stats_item.xml

<?xml version="1.0" encoding="utf-8"?><!--
/*
** Copyright 2008, 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.
*/
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal">

<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:paddingEnd="6dip"
android:paddingStart="12dip"
android:textAppearance="?android:attr/textAppearanceMedium" />

<TextView
android:id="@+id/last_time_used"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:paddingEnd="6dip"
android:paddingStart="12dip"
android:textAppearance="?android:attr/textAppearanceMedium" />

<TextView
android:id="@+id/usage_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:paddingEnd="6dip"
android:paddingStart="12dip"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

Values :-

arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<string-array name="usage_stats_display_order_types">
<item>Usage time</item>
<item>Last time used</item>
<item>App name</item>
</string-array>
</resources>

string.xml

 <string name="open_app_usage_setting">Open Apps with usage access settings</string>
<string name="last_time_used">"Last time used: "</string>
<string name="time_span">"Time span: "</string>

<string name="display_order_text">Sort by:</string>
<string name="app_name_label">App</string>
<string name="last_time_used_label">Last time used</string>
<!-- label for usage time -->
<string name="usage_time_label">Usage time</string>

user permissions :-

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>

resultant snap

How to find time spent on specific app?

You have to do two things for achieve that.

1. Start timer when user left your activity and goes to another app.

2. call background service using below code

private void check()     
{
ActivityManager actvityManager = (ActivityManager)
this.getSystemService( ACTIVITY_SERVICE );
List<ActivityManager.RunningAppProcessInfo> procInfos = actvityManager.getRunningAppProcesses();
for(int i = 0; i < procInfos.size(); i++)
{
if(procInfos.get(i).processName.equals("specific pacakgename here")) {

//check time here

}
}
}

How to track app usage time programmatically in android?

I would put data loges onResume and onPause methods. and on every onPause Append usage time to SharedPrefrences or some database and on requirements on create or when internet is turned on i would send usage statistics.

In this manner you can track every activities usage.

Not sure if some of the box methods exists.

How to detect an application foreground time?

I think the best option is to use lifecycle callback methods of your activities. The start time is onCreate() of the first activity you show to your user. The end time may be a bit more tricky. First of all, if you have multiple activities, user can exit any of them, so you need to track the currently opened activity and send the end-time only if the next activity doesn't appear. The second problem is which callback method should you use? onPause() isn't guaranteed to be called, and onDestroy() won't be called until the application is cleared from recents. So probablt onStop() is the right place.

Or you can use the callbacks of your application. Just derive from Application class and use it's callbacks for your time tracking.

Using usageStats.getTotalTimeInForeground() to get the time every application in a device spent in foreground

If you want to get the foreground running time of all applications in android lollipop use the following piece of code.

//Variables with dummy values and objects.

UsageStats usageStats;

String PackageName = "Nothing" ;

long TimeInforground = 500 ;

int minutes=500,seconds=500,hours=500 ;
UsageStatsManager mUsageStatsManager = (UsageStatsManager)getSystemService("usagestats");

long time = System.currentTimeMillis();

List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*10, time);

if(stats != null)
{
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats)
{

TimeInforground=usageStats.getTotalTimeInForeground();

PackageName=usageStats.getPackageName();

minutes = (int) ((TimeInforground / (1000*60)) % 60);

seconds = (int) (TimeInforground / 1000) % 60 ;

hours = (int) ((TimeInforground / (1000*60*60)) % 24);

Log.i("BAC", "PackageName is"+PackageName +"Time is: "+hours+"h"+":"+minutes+"m"+seconds+"s");

}

Make sure you have all right permissions in manifest file and app have access with usage under security in settings.

How to count app usage time while app is on foreground?

I've solved the issue.

Adding difference of current time and timestamp of current running app going foreground does the trick.

I just added the following code before the return statement:

UsageEvents.Event lastEvent = allEvents.get(allEvents.size() - 1);
if(lastEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
int diff = (int)System.currentTimeMillis() - (int)lastEvent.getTimeStamp();
diff /= 1000;
Integer prev = appUsageMap.get(lastEvent.getPackageName());
if(prev == null) prev = 0;
appUsageMap.put(lastEvent.getPackageName(), prev + diff);
}

It is pretty straightforward, I should have thought about it before posting the question.



Related Topics



Leave a reply



Submit