最近我在折腾一个
应用锁
的应用,里面有不少平时用很少接触的东西,整理记录下。
1.权限生擒
因为涉及到一下系统权限,所以常规的权限申请没用
- 先在
manifest
里登记下
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!--<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- 找系统要权限
//开始要:
private void checkPermission() {
if (!isStatAccessPermissionSet() && isNoOption()) {
UDialog.getInstance(this, false, false)
.showNoticeWithOnebtn("我要权限,给我。"),
(result, dia) -> {
//去系统权限页面
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivityForResult(intent, RESULT_ACTION_USAGE_ACCESS_SETTINGS);
});
} else {
toNext();
}
}
/**
* 查看是存在查看使用情况的应用程序界面
*/
private boolean isNoOption() {
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
List<ResolveInfo> list = packageManager
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
/**
* @return 判断是否已经获取 有权查看使用情况的应用程序 权限
*/
public boolean isStatAccessPermissionSet() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
PackageManager packageManager = getPackageManager();
ApplicationInfo info = packageManager
.getApplicationInfo(getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) context
.getSystemService(Context.APP_OPS_SERVICE);
appOpsManager
.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, info.uid, info.packageName);
return appOpsManager
.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, info.uid, info.packageName) ==
AppOpsManager.MODE_ALLOWED;
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
2.涉及到应用锁的相关方法
获取当前正在运行的桌面launcher包名
public String getLauncherPkgName() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
final ResolveInfo res = getPkgMgr().resolveActivity(intent, 0);
if (res.activityInfo == null) {
return null;// 一般不会发生
}
if (res.activityInfo.packageName.equals("android")) {
return null;// 有多个桌面程序存在,且未指定默认项时;
} else {
return res.activityInfo.packageName;
}
}
轻量: 获取栈顶应用包名(非系统程序在在栈顶时有效)
public String getCurTopAppPkg() {
ActivityManager am = (ActivityManager) KApp.getInstance().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> appTask = am.getRunningTasks(Integer.MAX_VALUE);
if (!UText.isEmpty(appTask)) {
return appTask.get(0).topActivity.getPackageName();
}
return "";
}
获取栈顶应用包名(所有程序有效)
public String getTopAppPkg() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
if (actMgr == null) {
actMgr = (ActivityManager) KApp.getInstance().getSystemService(Context.ACTIVITY_SERVICE);
}
List<ActivityManager.RunningTaskInfo> appTasks = actMgr.getRunningTasks(1);
if (null != appTasks && !appTasks.isEmpty()) {
return appTasks.get(0).topActivity.getPackageName();
}
} else {
//5.0以后需要用这方法
if (usgMgr == null) {
usgMgr = (UsageStatsManager) KApp.getInstance().getSystemService(Context.USAGE_STATS_SERVICE);
}
long endTime = System.currentTimeMillis();
long beginTime = endTime - 10000;
String result = "";
UsageEvents.Event event = new UsageEvents.Event();
UsageEvents usageEvents = usgMgr.queryEvents(beginTime, endTime);
while (usageEvents.hasNextEvent()) {
usageEvents.getNextEvent(event);
if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
result = event.getPackageName();
}
}
if (!android.text.TextUtils.isEmpty(result)) {
return result;
}
}
return "";
}
3.关于应用锁的实现
我觉的我这个方法效率并不太高,不知道大家有什么更高效的方法没?
我是后台启动一个服务,每隔一定时间扫描一次栈顶包名
大概是这样的:
//开启定时线程,1000 毫秒扫描一次
Disposable subscribe =Observable
.interval(1000, TimeUnit.MICROSECONDS)
.subscribe(aLong -> runCompare());
rxDisposable(subscribe);
private void runCompare() {
Disposable subscribe = Observable
.create((ObservableOnSubscribe<String>) emitter -> {
//锁总开关
if (Code.lockState.get()) {
String topName = UApps.instance().getTopApp();//获取栈顶app的包名
//返回桌面
if (!UText.isEmpty(topName) && topName.equals(Code.LauncherPkgName)) {
Code.doLock.set(true);//锁激活
lastPkgName = "";//上次解锁失效-置空
}
// ULog.commonD("【" + topName + "】【" + UApps.instance().getLauncherPkgName() + "】");
//栈顶包名在加锁列表
if (!UText.isEmpty(topName) && DbLockHelper.SearchByPkgName(topName) != null) {
emitter.onNext(topName);
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(lock -> {
ULog.commonD("【" + lastPkgName + "】--【" + Code.doLock.get() + "】--【" + lock + "】");
//锁可用
if (Code.doLock.get()) {
//包名为空 或者包名和上次解锁的不同
if (UText.isEmpty(lastPkgName) || !lastPkgName.equals(lock)) {
checkData(lock);//加锁
}
}
});
rxDisposable(subscribe);
}