9

我正在写一个启动器,它需要从系统中清除最近的应用程序/任务列表,而不是“没有在最近的任务列表中显示我的应用程序”,但我现在不知道。我在stackoverflow中搜索过,只有这个问题匹配,但答案没有任何帮助。其他人也问过同样的问题,他提到了来自 Android 4.0 的 RemoveTask。是的,我已经检查了 Android 2.3.7 和 Android 4.0 的源代码,大致估计,如果我可以删除 ActivityMangerService.Java 中定义的 mRecentTasks 列表,我想我几乎可以到达终点:

final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();

另一个可能有用的定义:

static ActivityManagerService mSelf;
public static ActivityManagerService self() {
    return mSelf;
}

因为我不熟悉 Java&refelction,所以我需要有关清除此列表的方式的帮助,以下是我的代码:

    public static <T> void clearRecentTaskList(Launcher launcher){
    ActivityManager am = (ActivityManager) launcher.getSystemService(Context.ACTIVITY_SERVICE);
    Object systemRecentTask = new ArrayList<T>();

    Object receiver = null;
    Field recentTaskList = null;
    Class<?> service = null;
    Field self = null;        


    try {
        service = Class.forName("com.android.server.am.ActivityManagerService");
        Log.d(LOG_TAG, "clearRecentTaskList, service gotton"+service.getName());
    } catch (ClassNotFoundException e2) {
        Log.d(LOG_TAG, "clearRecentTaskList, class service not found");
    }

    try {
        self = service.getDeclaredField("mSelf");
    } catch (SecurityException e2) {
        Log.d(LOG_TAG, "clearRecentTaskList, SecurityException during get mSelf");

    } catch (NoSuchFieldException e2) {
        Log.d(LOG_TAG, "clearRecentTaskList, NoSuchFieldException during get mSelf");
    }
    Log.d(LOG_TAG, "clearRecentTaskList, self  gotton " + self.toGenericString());

    try {
        self.setAccessible(true);
        receiver = self.get(null);
    } catch (IllegalArgumentException e2) {
        Log.d(LOG_TAG, "clearRecentTaskList, IllegalArgumentException during use self to get the receiver");
    } catch (IllegalAccessException e2) {
        Log.d(LOG_TAG, "clearRecentTaskList, IllegalAccessException during use self to get the receiver");
    }

    if ( receiver != null){
        Log.d(LOG_TAG, "clearRecentTaskList, receiver is : "+receiver.toString());
    } else {
        Log.d(LOG_TAG, "clearRecentTaskList, receiver is NULL");
    }


    try {
        recentTaskList = service.getDeclaredField("mRecentTasks");
        recentTaskList.setAccessible(true);
        Log.d(LOG_TAG, "clearRecentTaskList, recentTaskList gotton"+recentTaskList.toGenericString());

        try {
            systemRecentTask = recentTaskList.get(receiver);
        } catch (IllegalArgumentException e1) {
            Log.d(LOG_TAG, "IllegalArgumentException during try to clearRecentTask");
        } catch (IllegalAccessException e1) {
            Log.d(LOG_TAG, "IllegalAccessException during try to clearRecentTask");
        }

        Log.d(LOG_TAG, "Try to print the size of recent task: "+((ArrayList<T>) systemRecentTask).size());

    } catch (SecurityException e) {
        Log.d(LOG_TAG, "SecurityException during try to clearRecentTask");
    } catch (NoSuchFieldException e) {
        Log.d(LOG_TAG, "NoSuchFieldException during try to clearRecentTask");
    }   
}

使用此功能,我总是遇到“NullPointerException”,因为接收者是自己获得的空值。而且我尝试了另一种这样的方式(如果我删除所有的try/catch):

self = service.getDeclaredMethod("mSelf", null);
receiver = self.invoke(null, null); // mSelf is a static method which in ActivityMangerService class

同样的结果,我无法获取 ActivityManagerService 的实例,然后我无法获取 mRecentTasks。任何意见表示赞赏,虽然我不知道“如何删除此列表中的所有项目”,但这可能是另一个问题。

谢谢。

4

5 回答 5

1

虽然我本可以编辑我之前的答案,但我在另一个项目中使用的这个解决方案是如此全面不同(而且更容易),所以最好重新开始......

在这种情况下,我只是使用反射来访问 ActivityManager 的 removeTask() 方法,并将所有这些都包装到 MyActivityManager 的便利类中,如下所示:

import java.lang.reflect.Method;

public class MyActivityManager {


    private ActivityManager mActivityManager = null;
    private Method mRemoveTask;

    public MyActivityManager(Context context) {
        try {
            Class<?> activityManagerClass = Class.forName("android.app.ActivityManager");
            mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

            mRemoveTask = activityManagerClass.getMethod("removeTask", new Class[] { int.class, int.class });
            mRemoveTask.setAccessible(true);

        }
        catch ( ClassNotFoundException e ) {
            Log.i("MyActivityManager", "No Such Class Found Exception", e);
        }
        catch ( Exception e ) {
            Log.i("MyActivityManager", "General Exception occurred", e);
        }
    }

    /**
     * If set, the process of the root activity of the task will be killed
     * as part of removing the task.
     */
    public static final int REMOVE_TASK_KILL_PROCESS = 0x0001;

    /**
     * Completely remove the given task.
     *
     * @param taskId Identifier of the task to be removed.
     * @param flags Additional operational flags.  May be 0 or
     * {@link #REMOVE_TASK_KILL_PROCESS}.
     * @return Returns true if the given task was found and removed.
     */
    public boolean removeTask(int taskId, int flags) {
        try {
            return (Boolean) mRemoveTask.invoke(mActivityManager, Integer.valueOf(taskId), Integer.valueOf(flags) );
        } catch (Exception ex) {
            Log.i("MyActivityManager", "Task removal failed", ex);
        }
        return false;
    }

    public void clearRecentTasks() {
        List<RecentTaskInfo> recents = mActivityManager.getRecentTasks(1000, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
        // Start from 1, since we don't want to kill ourselves!
        for( int i=1; i < recents.size(); i++ ) {
            removeTask( recents.get(i).persistentId, 0);
        }
    }

}

然后,当我想清除最近的任务时,我会执行以下操作:

new MyActivityManager(this).clearRecentTasks();

可能需要其中一项或两项才能使其正常工作:

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.REORDER_TASKS" />

在我的情况下,应用程序是使用系统权限安装的。

于 2013-04-27T23:43:10.900 回答
1

我发现最好的方法是这样做:

public class BaseActivity extends Activity {
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

            Log.d("Focus debug", "Focus changed !");

        if(!hasFocus) {
            Log.d("Focus debug", "Lost focus !");

            Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(closeDialog);
        }
    }
}// all credit goes here: http://www.juliencavandoli.com/how-to-disable-recent-apps-dialog-on-long-press-home-button/

这不是我自己的代码,但这只是隐藏了最近的应用程序列表。

于 2013-12-06T09:57:44.940 回答
0

关于如何在此问题上执行此操作,这里有一些很好的线索:

改变 getRecentTasks 的结果

在这些之后,我出于自己的目的采取了以下方法(类似的情况,平板电脑被借给人们,然后有人必须在将它们交给下一个人之前“清除历史记录”)。

首先,在我的清单中,我创建了 18 个这样的任务:

<activity
  android:name=".nul.Null0"
  android:enabled="false"
  android:excludeFromRecents="false"
  android:exported="false"
  android:label="n0"
  android:launchMode="singleInstance"
  android:stateNotNeeded="true"
  android:taskAffinity=""
  android:theme="@android:style/Theme.Translucent.NoTitleBar" >
  <intent-filter>
    <action android:name="com.morphoss.blah.welcome.nul.Null0" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

其次,在助手启动“欢迎屏幕”以供下一个人使用平板电脑时启动的 AsyncTask 中,在清除浏览器历史记录和 cookie 后,我执行以下操作:

try {
    PackageManager pm = getPackageManager();
    ComponentName cn;
    Intent nullActivity;
    for( int i=0; i<19; i++ ) {
        cn = new ComponentName("com.morphoss.blah.welcome","com.morphoss.blah.welcome.nul.Null"+i);
        pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
        nullActivity = new Intent();
        nullActivity.setComponent(cn);
        nullActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(nullActivity);
        Thread.sleep(20);
    }
    Thread.sleep(100);
    for( int i=0; i<18; i++ ) {
        cn = new ComponentName("com.morphoss.blah.welcome","com.morphoss.blah.welcome.nul.Null"+i);
        pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    }
}
catch( Exception e) {
    if ( Constants.LOG_DEBUG ) Log.d(TAG,Log.getStackTraceString(e));
}

虽然我在每个任务的启动之间使用了“Thread.sleep(20)”,但我还没有完全检查那里需要什么,也许更短的时间可能会奏效。出于我的目的,在删除这些内容时延迟 1 秒是没有问题的。

最后的成分是正在启动的十八个(非常简单的)活动,如下所示:

package com.morphoss.blah.welcome.nul;

import android.app.Activity;
import android.os.Bundle;

public class Null0 extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.finish();
    }
}

希望这会有所帮助。

于 2012-10-21T08:40:25.867 回答
0

我刚刚遇到了同样的问题。好吧,我不知道最近的列表有多清晰,但我知道,如何不把你的应用放在那里。从: FLAG_ACTIVITY_NO_HISTORY 标志开始。

这对我有用,我希望我能帮助你。干杯,详细信息:最低 SDK 级别 14

于 2014-06-17T22:18:18.517 回答
0

从所有最近的任务中清除:

ActivityTaskManager.getService().removeAllVisibleRecentTasks();

于 2021-06-25T09:20:15.400 回答