UsageStatsManagerからアプリ使用履歴を取得する．

UsageStatsManagerからアプリの使用履歴を取得します．

# まえがき
私は，研究でユーザのアプリ使用履歴を取得し，解析を行っています．

目標は，スマートフォン側でアプリ使用履歴を取得し，このデータを蓄積させることです．

UsageStatsManagerは，細かい使用履歴を取ろうとすると，10日分ほどしか取得することができませんでした（頑張ればもっと取れるのかも…）．
そこで，一日に一度，バックグラウンドでその日一日分の使用履歴を取得し，アプリ内データにテキストファイルとして保存するようなアプリを作成します．こうすることで，何もしなくても使用履歴データが毎日取得できるわけです．

手順をまとめると
1. UsageStatsManagerからアプリの使用履歴を取得する．
1. テキストファイルとしてローカルに保存する．
1. WorkMangerを使って一日に一度データを取得できるようにする．

と言った具合です．

本記事では，1.の**UsageStatsManagerからアプリの資料履歴を取得する**という部分についてまとめます．

## 権限の取得
UsageStatsManagerを取得するには，ユーザからのアクセス許可が必要です．
ここでは，アクティビティが起動した際に，権限の有無を確認し，権限がない場合にそれを催促します．

### 権限の有無の確認
Android Q以降とその前で確認方法が異なりますので，それに対応できるように実装します．
自分はMainActivity内にチェック用の関数を用意しました．

```MainActivity.kt
    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を取得します．


```PermissionDemandScreen.kt
@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()`について詳しくは[こちら](https://www.javadrive.jp/start/calendar/index4.html)．

本稿では，30日前までを追加しています．

`context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager`この部分でUsageStatsManagerを取得します．

```Kotlin
return usageStatsManager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY,
            cal.timeInMillis,
            System.currentTimeMillis()
        )
```
こちらの部分で，最終的に`List<UsageStats>`を返しています．

`INTERVAL_DAILY`の部分を変えることでクエリの間隔を変えることができます．
`cal.timeInMillins`はUsageStatsを取得する開始時間です．
`System.currentTimeMillis()`はUsageStatsを取得する最終時間です．コードでは現在時刻としています．

↓コード全体

```GetUsageStats.kt
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参照)