最近遇到這樣的一個需求,獲取使用者當前正在使用的App。
在Android5.0之前,使用下面的程式碼即可獲得相關資訊:
//5.0及以下
private fun getTopAppOld(context: Context) {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val topActivity = activityManager.getRunningTasks(1)[0].topActivity.packageName
(context as TopAppInfoService).showToast(TopAppInfoService.getAppName(context, topActivity) + ":" + topActivity)
}
複製程式碼
但是5.0以後此方法就不行了,需要使用UsageStatsManager應用使用資料統計服務。
使用UsageStatsManager應用使用資料統計服務需要使用者手動授權。
startActivityForResult(
new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS),MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS);
複製程式碼
同時需要在註冊檔案中註冊許可權
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions"/>
複製程式碼
我們可以同下面的方法判斷是否取得許可權:
//檢測使用者是否對本app開啟了“Apps with usage access”許可權
private boolean hasPermission() {
AppOpsManager appOps = (AppOpsManager)
getSystemService(Context.APP_OPS_SERVICE);
int mode = 0;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
}
return mode == AppOpsManager.MODE_ALLOWED;
}
複製程式碼
取得許可權之後,就可以啟動一個後的service來監聽當前使用者使用的App。
import android.app.ActivityManager
import android.app.Service
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import android.widget.Toast
import java.util.concurrent.TimeUnit
class TopAppInfoService : Service() {
private var myThread: MyThread? = null
class MyThread constructor(private val context: Context) : Thread() {
private var isRun = true
fun setStop() {
isRun = false
}
override fun run() {
while (isRun) {
try {
TimeUnit.SECONDS.sleep(2)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getTopAppNew(context)
} else {
getTopAppOld(context)
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}
//5.0及以下
private fun getTopAppOld(context: Context) {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val topActivity = activityManager.getRunningTasks(1)[0].topActivity.packageName
(context as TopAppInfoService).showToast(TopAppInfoService.getAppName(context, topActivity) + ":" + topActivity)
}
//5.0及以上
private fun getTopAppNew(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val m = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
if (m != null) {
val now = System.currentTimeMillis()
//獲取60秒之內的應用資料
val stats = m.queryUsageStats(UsageStatsManager.INTERVAL_BEST, now - 60 * 1000, now)
Log.i(TAG, "Running app number in last 60 seconds : " + stats!!.size)
var topActivity = ""
//取得最近執行的一個app,即當前執行的app
if (stats != null && !stats.isEmpty()) {
var j = 0
for (i in stats.indices) {
if (stats[i].lastTimeUsed > stats[j].lastTimeUsed) {
j = i
}
}
topActivity = stats[j].packageName//包名
}
if (!topActivity.isEmpty()) {
(context as TopAppInfoService).showToast(TopAppInfoService.getAppName(context, topActivity) + ":" + topActivity)
}
}
}
}
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
myThread = MyThread(this)
myThread!!.start()
Log.i(TAG, "Service is start.")
}
override fun onDestroy() {
super.onDestroy()
myThread!!.setStop()
Log.i(TAG, "Service is stop.")
}
fun showToast(txt: String?) {
if (txt == null) {
Log.e(TAG, "call method showToast, text is null.")
return
}
val handler = Handler(Looper.getMainLooper())
handler.post {
Toast.makeText(this@TopAppInfoService, txt, Toast.LENGTH_LONG)
.show()
}
}
companion object {
val TAG = "TopAppInfoService"
fun getAppName(context: Context, packageName: String): String {
val pm = context.packageManager
var Name: String
try {
Name = pm.getApplicationLabel(pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA)).toString()
} catch (e: PackageManager.NameNotFoundException) {
Name = ""
}
return Name
}
}
}
複製程式碼
上面對Android5.0做了相容,可以拿到App的包名和應用名。
剩下的就是在適當的時候啟動服務了:
btnStart = (Button) this.findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TopAppInfoService.class);
startService(intent);
}
});
btnStop = (Button) this.findViewById(R.id.btnStop);
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TopAppInfoService.class);
stopService(intent);
}
});
複製程式碼
在華為,小米和一加的真機上通過測試,請放心食用。
祝你生活愉快。