Android StudioでUsageStatsManagerを使う方法(他のアプリの起動時間を調べる方法)

## 前提

Windows 10
Android Studio最新版
Java

**この方法は、2020/02/27時点では私のスマートフォンのおいては正常に動作しました。**
**仕様変更があるかもしれないので、コピペしてうまく行かない場合は公式ドキュメントを参考にしましょう。**

## やりたいこと

他のアプリがその日どれくらい起動していたかを取得する必要がありました。
例えば、下の画像はActionDashというアプリで、他のアプリの起動時間を表示しています。
[](
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183842/204c2e67-128d-8889-6ae4-172c6a1155a8.png)
)

結論から言うと、[UsageStatsManager](https://developer.android.com/reference/android/app/usage/UsageStatsManager)を使えば良いです。

## UsageStatsManager

### 権限関係

まず、下のように`AndroidManifest.xml`に記載してください。

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="****">

    <!-- 下の二行を追加 -->
    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
        tools:ignore="ProtectedPermissions" />

    <application>
         <!-- 省略 -->
    </application>

</manifest>
```

次に、permission checkを行います。
普通のpermissionの方法ではなく、特別な方法を使用します。

```javascript
private boolean checkReadStatsPermission() {
  // AppOpsManagerを取得
  AppOpsManager aom = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
  // GET_USAGE_STATSのステータスを取得
  int mode = aom.checkOp(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), getPackageName());
  if (mode == AppOpsManager.MODE_DEFAULT) {
    // AppOpsの状態がデフォルトなら通常のpermissionチェックを行う。
    // 普通のアプリならfalse
    return checkPermission("android.permission.PACKAGE_USAGE_STATS", android.os.Process.myPid(), android.os.Process.myUid()) == PackageManager.PERMISSION_GRANTED;
  }
  // AppOpsの状態がデフォルトでないならallowedのみtrue
  return mode == AppOpsManager.MODE_ALLOWED;
}
```

最後に、permissionのリクエストです。
これも、通常の方法と違うので注意が必要です。

```java
if (!checkReadStatsPermission()) {
  startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
}
```

### UsageStatsManagerを使う

ソースコードの中で解説を入れています。
このソースコードは、その日のアプリの使用時間を取得します。


```java

public class UsageStatsClass {
  // Log.d()で、このクラスが出力したものだと識別するための名前
  private static final String TAG = UsageStatsClass.class.getSimpleName();
  // MainActivityのContextを代入
  private Context context;

  public UsageStatsClass(Context mContext) {
    // contextを代入
    context = mContext;
  }

  // UsageStatsというObjectは、一つのアプリの情報(アプリの使用時間など)が入っている
  // つまり、1つアプリにつき1つのUsageStatsが割り当てられる
  private List<UsageStats> getUsageStatsObject() {
    // getSystemService()で、UsageStatsManagerを取得する
    // UsageStatsManagerは、アプリの使用情報を取得するためのもの
    UsageStatsManager usageStatsManager =
            (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);

    // 現在時刻をCalendarオブジェクトとして取得する
    Calendar calendar = Calendar.getInstance();
    // calendarの時刻を午前0時に設定する
    // これにより、calendarが内包している時刻情報は、現在時刻から本日の午前0時となる
    calendar.set(Calendar.HOUR_OF_DAY, 0);

    // queryUsageStats(取得する時間の単位, 取得する時間の始まり、取得する時間の終わり)
    // 取得する時間の単位 : 日単位(INTERVAL_DAILY)、週単位(INTERVAL_WEEKLY)、月単位(INTERVAL_MONTHLY)、
    //                    年単位(INTERVAL_YEARLY)、自動選択(INTERVAL_BEST)がある
    // 
    // 取得する時間の始まり : 取得したいデータの時間帯のスタート地点。今回は、その日の午前0時。
    // 取得する時間の終わり : 取得したいデータの時間帯の終わり。今回は、現在時刻。
    return usageStatsManager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY,
            calendar.getTimeInMillis(),
            System.currentTimeMillis());
  }

  // 外部から実行するための関数
  public void readOneDayUsageStats() {
    // アプリごとの使用情報をListとして取得
    List<UsageStats> usageStats = getUsageStatsObject();

    // for文を使用することで、usageStatに一つのアプリの使用情報を取得する
    for (UsageStats usageStat : usageStats) {
      // もし、そのアプリを一度も使用していない場合は、スキップする
      if (usageStat.getTotalTimeInForeground() == 0) {
        continue;
      }

      // Logcatで、取得した情報を出力する
      // package name : getPackageName() : そのアプリ固有のID
      // total time displayed : getTotalTimeInForeground() : そのアプリが画面上に表示された合計時間
      // first time : getFirstTimeStamp() : 取得したデータの始まりの時間をミリ秒で返す
      // getStringDate()を使ってミリ秒を人間にわかりやすい形に変換している
      // end time : getLastTimeUsed() : 取得したデータの終わりの時間をミリ秒で返す
      // getStringDate()を使ってミリ秒を、人間にわかりやすい形に変換している
      Log.d(TAG, "packageName: " + usageStat.getPackageName() + "\ttotalTimeDisplayed: " + usageStat.getTotalTimeInForeground()
          + "\tfirstTime: " + getStringDate(usageStat.getFirstTimeStamp()) + "\tlastTime: " + getStringDate(usageStat.getLastTimeUsed()));
    }
  }

  // long型のミリ秒をString型の人間がわかりやすい形に変換する
  private String getStringDate(long milliseconds) {
    final DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.JAPANESE);
    final Date date = new Date(milliseconds);
    return df.format(date);
  }
}

```

### 実行結果

アプリごとの、時間が表示されています。
やったね！

```
D/UsageStatsClass: packageName: com.huawei.android.launcher	totalTimeDisplayed: 3769989	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 15:59:00
D/UsageStatsClass: packageName: jp.naver.line.android	totalTimeDisplayed: 805413	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 15:34:36
D/UsageStatsClass: packageName: com.discord	totalTimeDisplayed: 4247	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 15:43:05
D/UsageStatsClass: packageName: com.microsoft.office.outlook	totalTimeDisplayed: 43011	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 14:19:16
D/UsageStatsClass: packageName: com.google.android.packageinstaller	totalTimeDisplayed: 2444	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 15:59:02
D/UsageStatsClass: packageName: com.google.android.apps.photos	totalTimeDisplayed: 283917	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 13:38:33
D/UsageStatsClass: packageName: com.spotify.music	totalTimeDisplayed: 6267989	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 13:56:21
D/UsageStatsClass: packageName: jp.mineo.app.phone	totalTimeDisplayed: 70175	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 13:59:50
D/UsageStatsClass: packageName: com.google.android.apps.translate	totalTimeDisplayed: 8170	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 15:04:14
D/UsageStatsClass: packageName: ch.bitspin.timely	totalTimeDisplayed: 798142	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 11:17:25
D/UsageStatsClass: packageName: com.android.settings	totalTimeDisplayed: 21715	firstTime: 2020/02/27 00:00:02	lastTime: 2020/02/27 14:32:32
```




## 参考文献

 * https://developer.android.com/reference/android/app/usage/UsageStatsManager
 * https://qiita.com/wasnot/items/6074dbcdd49141f8e7d8
 * https://codechacha.com/ja/android-app-usage-stats/
 * https://developer.android.com/reference/java/util/Calendar