–分两种情况处理,
低于5.0:使用getRunningTasks
高于5.0:使用,PACKAGE_USAGE_STATE 查看使用情况的这个权限
这个权限,只能系统app使用,要使用,需要在该权限后面添加上忽略,并且在用户使用时,给用户自己来打开app的查看使用情况的权利。这个权限不属于6.0权限,使用其他方式动态申请该权限无效。
使用场景:
定时打印app的栈顶app 所在的包名称
Demo场景实例:
创建一个服务,服务里面设置一个定时器,每隔5s打印一次栈顶app所在的包名,在布局文件中,设置一个按钮,用于打开这个服务。
1、添加权限
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
2、服务的设置
注意: 服务 需要在清单文件中进行注册
/**
* 自定义服务 时刻记录手机的栈顶activity 所在包
*/
public class TopAppService extends Service {
private Timer timer;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TopAppService", "服务执行了");
if (timer == null) {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
//判断是否有use 查看使用情况的权限
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
boolean useGranted = isUseGranted();
Log.e("TopAppService", "use 权限 是否允许授权=" + useGranted);
if (useGranted) {
String topApp = getHigherPackageName();
Log.e("TopAppService", "顶层app=" + topApp);
} else {
//开启应用授权界面
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} else {
String topApp = getLowerVersionPackageName();
Log.e("TopAppService", "顶层app=" + topApp);
}
}
}, 0, 5000);//每隔5s 执行一次
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 判断 用户查看使用情况的权利是否给予app
*
* @return
*/
private boolean isUseGranted() {
Context appContext = MyApplication.getAppContext();
AppOpsManager appOps = (AppOpsManager) appContext
.getSystemService(Context.APP_OPS_SERVICE);
int mode = -1;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
mode = appOps.checkOpNoThrow("android:get_usage_stats",
android.os.Process.myUid(), appContext.getPackageName());
}
boolean granted = mode == AppOpsManager.MODE_ALLOWED;
return granted;
}
/**
* 高版本:获取顶层的activity的包名
*
* @return
*/
private String getHigherPackageName() {
String topPackageName = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
//time - 1000 * 1000, time 开始时间和结束时间的设置,在这个时间范围内 获取栈顶Activity 有效
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
// Sort the stats by the last time used
if (stats != null) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
Log.e("TopPackage Name", topPackageName);
}
}
} else {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ComponentName topActivity = activityManager.getRunningTasks(1).get(0).topActivity;
topPackageName = topActivity.getPackageName();
}
return topPackageName;
}
/**
* 低版本:获取栈顶app的包名
*
* @return
*/
private String getLowerVersionPackageName() {
String topPackageName;//低版本 直接获取getRunningTasks
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ComponentName topActivity = activityManager.getRunningTasks(1).get(0).topActivity;
topPackageName = topActivity.getPackageName();
return topPackageName;
}
}
获取高版本栈顶app所在的包名,方案来自于网络,这里只是个人记录解决方案。
ps,此处有问题
打算优化一下代码,整理下代码,就将获取栈顶app的高版本方式和低版本方式整合为一个方法了,最后竟然报错了,编译不通过
Error:Execution failed for task ':app:transformClassesWithInstantRunForDebug'.
> java.lang.ClassNotFoundException: android.app.usage.UsageStatsManager
说是找不到这个类,照上面的方式编译却能通过,在修改过程中,我也没有修改逻辑,为什么上面的方式就能够通过,我整合在一起写就有问题了呢?
—网上百度这个错误,也没找到合理的说话,任然存在疑惑。
猜测:和编译器有关,编译器对当前项目的编译,会将与将该版本下的相关的方法都进行编译,该版本下要调用哪个方法,那个方法就会被编译。
创建两个方法(高版本和低版本)时:在低版本上面执行,由于是直接调用的获取低版本的方法,高版本的方法不会被编译。
如果将两个方法整合到一起,那么在低版本上面执行时,调用这个方法之后,这个方法就要被编译,而高版本的相关类在低版本上是不存在的。所以就报了上面的错。
3、通过按钮 开启服务
Intent intent = new Intent(this, TopAppService.class);
startService(intent);
4、运行效果
模拟器(版本号17) 运行效果—低版本
手机(乐视2 android6.0)运行效果—高版本
在手机上,没有查看使用情况权利时跳转到授权界面
这里我已经将GetTopActivity 的权限开启了。
手机上执行时的log信息:
5、主要demo文件下载地址
主要涉及:
MainActivity.java
MyApplication.java
TopAppService.java
AndroidManifest.xml
http://download.csdn.net/detail/u012391876/9716756