LoginSignup
8
7

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-02-27

前提

Windows 10
Android Studio最新版
Java

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

やりたいこと

他のアプリがその日どれくらい起動していたかを取得する必要がありました。
例えば、下の画像はActionDashというアプリで、他のアプリの起動時間を表示しています。

結論から言うと、UsageStatsManagerを使えば良いです。

UsageStatsManager

権限関係

まず、下のようにAndroidManifest.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の方法ではなく、特別な方法を使用します。

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のリクエストです。
これも、通常の方法と違うので注意が必要です。

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

UsageStatsManagerを使う

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


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

参考文献

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7