仿Android L 长按Home键显示最近使用应用信息及清理
2015-08-06 18:52
651 查看
Android L 上,长按Home键可以显示最近使用的应用,以便用户可以快速回到之前使用的应用。
现在项目需要用程序把栈信息清空=_=
下面是实现过程,分析源码的实现过程:
源码应用到了ActivityManager的removeTask()方法来清除,获取是应用RecentTask类。
在网上找了下资料,资料不多,找到一篇很有用http://blog.csdn.net/yanbin1079415046/article/details/8026613,谢谢作者。
他分析了系统的处理过程,并模拟系统给出了一个获取历史栈的方法。
(1)通过Activity的getRecentTasks方法获取近来历史栈的信息。
(2)根据ActivityManager.RecentTaskInfo 获取对应Activity以及对应的应用信息。
接下来是如何清除的问题。
阅读ActivityManager源码,am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
是一个系统隐藏方法,所以我们通过反射调用这个方法。
需要传入两个字段。
第一个字段:可以通过getRecentTasks获取
第二个字段:ActivityManager.REMOVE_TASK_KILL_PROCESS是个隐藏字段,直接把值从源码中读出传入。
perfect!测试会出现异常:没有remove_Tasks权限。
这个权限需要系统级别的权限才能实现。
因而manifest.xml里配置如下:
设置sharedUserId=Android.uid.system
并设置权限需要的权限
然后将它和目标系统共同编译,并放到系统分区,这样就有了系统权限,就可以运行了。本方法只适用于定制。如果想要做一个app在普通的设备上实现这个功能,恐怕就不行了,主要是remove_Tasks这个系统级别权限的问题。
现在项目需要用程序把栈信息清空=_=
下面是实现过程,分析源码的实现过程:
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { final boolean handled = super.onKeyDown(keyCode, event); if (keyCode==KeyEvent.KEYCODE_ENTER && event.isLongPress()) { // index is reverse since most recent appears at the bottom... int taskSize = mRecentTaskDescriptions.size(); for(int ii=0;ii<taskSize;ii++){ TaskDescription ad = mRecentTaskDescriptions.get(0); if (ad == null) { return true; } mRecentTaskDescriptions.remove(ad); mRecentTasksLoader.remove(ad); // Handled by widget containers to enable LayoutTransitions properly // mListAdapter.notifyDataSetChanged(); if (mRecentTaskDescriptions.size() == 0) { dismissAndGoBack(); } // Currently, either direction means the same thing, so ignore direction and remove // the task. final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); if (am != null) { am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS); // Accessibility feedback setContentDescription( mContext.getString(R.string.accessibility_recents_item_dismissed, ad.getLabel())); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); setContentDescription(null); } } return true; } return handled; }
源码应用到了ActivityManager的removeTask()方法来清除,获取是应用RecentTask类。
在网上找了下资料,资料不多,找到一篇很有用http://blog.csdn.net/yanbin1079415046/article/details/8026613,谢谢作者。
他分析了系统的处理过程,并模拟系统给出了一个获取历史栈的方法。
// 得到包管理器和activity管理器 final Context context = this; final PackageManager pm = context.getPackageManager(); final ActivityManager am = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); // 从ActivityManager中取出用户最近launch过的 MAX_RECENT_TASKS + 1 个,以从早到晚的时间排序, // 注意这个 0x0002,它的值在launcher中是用ActivityManager.RECENT_IGNORE_UNAVAILABLE // 但是这是一个隐藏域,因此我把它的值直接拷贝到这里 final List<ActivityManager.RecentTaskInfo> recentTasks = am .getRecentTasks(MAX_RECENT_TASKS + 1, 0x0002); // 这个activity的信息是我们的launcher ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory( Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0); int numTasks = recentTasks.size(); for (int i = 0; i < numTasks && (i < MAX_RECENT_TASKS); i++) { HashMap<String, Object> singleAppInfo = new HashMap<String, Object>();// 当个启动过的应用程序的信息 final ActivityManager.RecentTaskInfo info = recentTasks.get(i); Intent intent = new Intent(info.baseIntent); Log.e("", "###" + info.persistentId); appIds.add(info.persistentId); if (info.origActivity != null) { intent.setComponent(info.origActivity); } // TODO 测试用,无意义代码 String currentInfo = "PackageName==" + intent.getComponent().getPackageName() + ",ClassName==" + intent.getComponent().getClassName(); /** * 如果找到是launcher,直接continue,后面的appInfos.add操作就不会发生了 */ if (homeInfo != null) { if (homeInfo.packageName.equals(intent.getComponent() .getPackageName()) && homeInfo.name.equals(intent.getComponent() .getClassName())) { MAX_RECENT_TASKS = MAX_RECENT_TASKS + 1; continue; } } // 设置intent的启动方式为 创建新task()【并不一定会创建】 intent.setFlags((intent.getFlags() & ~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) | Intent.FLAG_ACTIVITY_NEW_TASK); // 获取指定应用程序activity的信息(按我的理解是:某一个应用程序的最后一个在前台出现过的activity。) final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); if (resolveInfo != null) { final ActivityInfo activityInfo = resolveInfo.activityInfo; final String title = activityInfo.loadLabel(pm).toString(); Drawable icon = activityInfo.loadIcon(pm); if (title != null && title.length() > 0 && icon != null) { singleAppInfo.put("title", title); singleAppInfo.put("icon", icon); singleAppInfo.put("tag", intent); } } appInfos.add(singleAppInfo); } MAX_RECENT_TASKS = repeatCount; for (HashMap<String, Object> map : appInfos) { Log.e("", "@" + map.get("title")); }
(1)通过Activity的getRecentTasks方法获取近来历史栈的信息。
(2)根据ActivityManager.RecentTaskInfo 获取对应Activity以及对应的应用信息。
接下来是如何清除的问题。
阅读ActivityManager源码,am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
是一个系统隐藏方法,所以我们通过反射调用这个方法。
需要传入两个字段。
第一个字段:可以通过getRecentTasks获取
第二个字段:ActivityManager.REMOVE_TASK_KILL_PROCESS是个隐藏字段,直接把值从源码中读出传入。
private void removeTasks() { ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); Class<ActivityManager> clazz = ActivityManager.class; Method method; for (int id : appIds) { try { method = clazz.getDeclaredMethod("removeTask", int.class, int.class); method.setAccessible(true); try { method.invoke(am, id, 0x0001); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
perfect!测试会出现异常:没有remove_Tasks权限。
这个权限需要系统级别的权限才能实现。
因而manifest.xml里配置如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gi.test" android:versionCode="1" android:versionName="1.0" android:sharedUserId="android.uid.system" > <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" />
设置sharedUserId=Android.uid.system
并设置权限需要的权限
然后将它和目标系统共同编译,并放到系统分区,这样就有了系统权限,就可以运行了。本方法只适用于定制。如果想要做一个app在普通的设备上实现这个功能,恐怕就不行了,主要是remove_Tasks这个系统级别权限的问题。
相关文章推荐
- Android布局优化
- android textview 超链接跳转到浏览器
- Android中 View not attached to window manager错误的解决办法
- android中使用LocationManager定位获取信息
- android Log.isLoggable方法的使用
- Android笔记(三) 使得Activity之间可以跳转---Intent
- Android页面跳转的方法
- Android复习笔记(13)-Fragment的使用(1)
- 三种方法使android 手机执行 二进制程序
- Android实现水波纹外扩效果
- Android WebView加载本地CSS
- 【Android】五大布局
- 在线阅读android源码
- Android的RelativeLayout的view的layout_marginBottom不起作用
- AndroidStudio单元测试——instrumentation
- Android Activity 的四种启动模式 lunchMode 和 Intent.setFlags()
- Android使用WindowManager在界面添加一个悬浮框
- Android基础动画
- android 自定义radiobutton的样式 实现自己想要的样子
- android Bitmap->BGR字节数组