UsageStatsManagerからアプリの使用履歴を取得します.
まえがき
私は,研究でユーザのアプリ使用履歴を取得し,解析を行っています.
目標は,スマートフォン側でアプリ使用履歴を取得し,このデータを蓄積させることです.
UsageStatsManagerは,細かい使用履歴を取ろうとすると,10日分ほどしか取得することができませんでした(頑張ればもっと取れるのかも…).
そこで,一日に一度,バックグラウンドでその日一日分の使用履歴を取得し,アプリ内データにテキストファイルとして保存するようなアプリを作成します.こうすることで,何もしなくても使用履歴データが毎日取得できるわけです.
手順をまとめると
- UsageStatsManagerからアプリの使用履歴を取得する.
- テキストファイルとしてローカルに保存する.
- WorkMangerを使って一日に一度データを取得できるようにする.
と言った具合です.
本記事では,1.のUsageStatsManagerからアプリの資料履歴を取得するという部分についてまとめます.
権限の取得
UsageStatsManagerを取得するには,ユーザからのアクセス許可が必要です.
ここでは,アクティビティが起動した際に,権限の有無を確認し,権限がない場合にそれを催促します.
権限の有無の確認
Android Q以降とその前で確認方法が異なりますので,それに対応できるように実装します.
自分はMainActivity内にチェック用の関数を用意しました.
private fun checkUsageStatsPermission(): Boolean{
val appOpsManager = getSystemService(APP_OPS_SERVICE) as AppOpsManager
val mode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
//Q以降の場合のチェック
appOpsManager.unsafeCheckOpNoThrow("android:get_usage_stats", Process.myUid(), packageName)
}else {
//Q以前の場合のチェック
appOpsManager.checkOpNoThrow("android:get_usage_stats", Process.myUid(), packageName)
}
return mode == AppOpsManager.MODE_ALLOWED
}
権限の取得
権限を持っていない場合は,権限をユーザから与えてもらいます.
自分は権限がない場合,権限を付加を促すためのスクリーンを作りました.
インテントを使って,権限付与画面に遷移させます.
Activity(context)が必要になるため,LocalContext.current as Activity
を使って@Composable
内でActivityを取得します.
@Composable
fun PermissionDemandScreen(
transitionMain: () -> Unit,
modifier: Modifier = Modifier
) {
//アクティビティを取得する
val activity = LocalContext.current as Activity
Column(
...
) {
...
Button(
onClick = {
requestPermission(activity)
transitionMain()
}
) {
Text(text = "設定を開く")
}
}
}
private fun requestPermission(activity: Activity){
activity.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
UsageStatsManagerの取得部分を作る
UsageStatsManagerを取得する部分を作ります.
取得したい形式によって,各々変えてもらいたいですが,私はList<UsageStats>
を返す関数を作成しています.
UsageStatsManagerを取得するために,引数にはcontext: Context
を設定しています.
getUsageStats
でUsageStatsManagerを取得しています.
カレンダーのインスタンスを作り,cal.add()
の部分で取得する期間が指定できます.
Calender.add()
について詳しくはこちら.
本稿では,30日前までを追加しています.
context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
この部分でUsageStatsManagerを取得します.
return usageStatsManager.queryUsageStats(
UsageStatsManager.INTERVAL_DAILY,
cal.timeInMillis,
System.currentTimeMillis()
)
こちらの部分で,最終的にList<UsageStats>
を返しています.
INTERVAL_DAILY
の部分を変えることでクエリの間隔を変えることができます.
cal.timeInMillins
はUsageStatsを取得する開始時間です.
System.currentTimeMillis()
はUsageStatsを取得する最終時間です.コードでは現在時刻としています.
↓コード全体
private const val TAG = "GetUsageStats"
class GetUsageStats(
private val context: Context
) {
fun getUsageStats(): List<UsageStats>{
Log.i(TAG,"Accessed GetUsageStatsClass")
return sortedUsageStats( getAppUsageStats())
}
private fun getAppUsageStats(): MutableList<UsageStats> {
val cal = Calendar.getInstance()
cal.add(Calendar.DAY_OF_YEAR, -30)
// usageStatsManagerのオブジェクトの取得
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
return usageStatsManager.queryUsageStats(
UsageStatsManager.INTERVAL_DAILY,
cal.timeInMillis,
System.currentTimeMillis()
)
}
private fun sortedUsageStats(usageStats: MutableList<UsageStats>): List<UsageStats> {
usageStats.sortWith(
compareBy { it.lastTimeUsed }
)
return usageStats
}
}
余談ですが,sortedUsageStats
の部分で使用時間順にソートしています.
どこかで取得する.
MainActivityなどで,GetUsageのインスタンスを作成し,getUsageStats()
を呼び出すことでList<UsageStats>
が取得できます.
まとまったコードは https://github.com/M0710Fa/AccumulateUsage にあります.
参考
[1] Android Developers, UsageStatsManager, https://developer.android.com/reference/android/app/usage/UsageStatsManager (2022/10/13参照)
[2] codechacha.com, アンドロイド - UsageStatsManagerでアプリ履歴を取得する, https://codechacha.com/ja/android-app-usage-stats/ (2022/10/13参照)