您的位置:首页 > 移动开发 > Android开发

仿Android L 长按Home键显示最近使用应用信息及清理

2015-08-06 18:52 651 查看
Android L 上,长按Home键可以显示最近使用的应用,以便用户可以快速回到之前使用的应用。

现在项目需要用程序把栈信息清空=_=

下面是实现过程,分析源码的实现过程:

@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这个系统级别权限的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: