近期任务框(就是近期打开过的应用)其实也就是一个系统级别的对话框,就是长按手机的HOME键弹出的视图。

源码中的路径为:D:\tools\android4.0.1\frameworks\base\policy\src\com\android\internal\policy\impl\RecentApplicationsDialog.java

1,显示方式,该对话框在PhoneWindowManager (路径和RecentApplicationsDialog.java同样)类中的showRecentAppsDialog方法

  /**     * Create (if necessary) and launch the recent apps dialog, or hide it if it is     * already shown.     */    void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {        mHandler.post(new Runnable() {            @Override            public void run() {                if (mRecentAppsDialog == null) {                    mRecentAppsDialog = new RecentApplicationsDialog(mContext);                }                if (mRecentAppsDialog.isShowing()) {                    if (dismissIfShown) {                        mRecentAppsDialog.dismiss();                    }                } else {                    mRecentAppsDialog.setHeldModifiers(heldModifiers);                    mRecentAppsDialog.show();                }            }        });    }

2,创建对话框时配置一些参数:比如填充父窗体,没有标题,更重要的一点就是设成系统级别的对话框。

/** * 我们创建最近的应用程序对话框只是一次,它会留下(隐藏),直到用户激活。 *  * @see 调用显示是在这个类里(PhoneWindowManager#showRecentAppsDialog) */@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Context context = getContext();if (sStatusBar == null) {sStatusBar = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);}//获取窗体,注意:window是整个手机屏幕的窗体,而不仅仅但是对话框的窗体Window window = getWindow();//设置无标题window.requestFeature(Window.FEATURE_NO_TITLE);//将该对话框设置成系统级别对话框window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);window.setTitle("Recents");setContentView(com.android.internal.R.layout.recent_apps_dialog);//设置对话框的参数:宽、高为填充父窗体final WindowManager.LayoutParams params = window.getAttributes();params.width = WindowManager.LayoutParams.MATCH_PARENT;params.height = WindowManager.LayoutParams.MATCH_PARENT;window.setAttributes(params);window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);mIcons[0] = (TextView) findViewById(com.android.internal.R.id.button0);mIcons[1] = (TextView) findViewById(com.android.internal.R.id.button1);mIcons[2] = (TextView) findViewById(com.android.internal.R.id.button2);mIcons[3] = (TextView) findViewById(com.android.internal.R.id.button3);mIcons[4] = (TextView) findViewById(com.android.internal.R.id.button4);mIcons[5] = (TextView) findViewById(com.android.internal.R.id.button5);mIcons[6] = (TextView) findViewById(com.android.internal.R.id.button6);mIcons[7] = (TextView) findViewById(com.android.internal.R.id.button7);mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);//为每个TextView设置点击事件for (TextView b : mIcons) {b.setOnClickListener(this);}}


3,为八个按钮载入最近的活动,如果最近打过的应用任务栈中超过8个也只能取八个

/** * 为八个按钮载入最近的活动,如果最近打过的应用任务栈中超过8个也只能取八个, */private void reloadButtons() {final Context context = getContext();final PackageManager pm = context.getPackageManager();final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);//这里是获取近期打开过的应用的RecentTaskInfofinal List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasks(MAX_RECENT_TASKS,ActivityManager.RECENT_IGNORE_UNAVAILABLE);ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);IconUtilities iconUtilities = new IconUtilities(getContext());// 性能注意:android性能指南推荐迭代器来遍历集合,因为知道getRecentTasks()总是返回一个ArrayList// < >,我们将使用一个简单的指数相反。int index = 0;int numTasks = recentTasks.size();for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) {final ActivityManager.RecentTaskInfo info = recentTasks.get(i);// 目的用于调试,但不允许第一个结果创建一个空的列表if (DBG_FORCE_EMPTY_LIST && (i == 0))continue;Intent intent = new Intent(info.baseIntent);if (info.origActivity != null) {intent.setComponent(info.origActivity);}// 跳过当前Launcher数据,就是不把当前launcher作为近期打开过的任务。if (homeInfo != null) {if (homeInfo.packageName.equals(intent.getComponent().getPackageName())&& homeInfo.name.equals(intent.getComponent().getClassName())) {continue;}}//下面做的其实就是封装一些数据给每一个对应的TextViewintent.setFlags((intent.getFlags() & ~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)| Intent.FLAG_ACTIVITY_NEW_TASK);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) {final TextView tv = mIcons[index];tv.setText(title);icon = iconUtilities.createIconDrawable(icon);tv.setCompoundDrawables(null, icon, null, null);RecentTag tag = new RecentTag();tag.info = info;tag.intent = intent;//关于setTag这个是view中集成的一个神奇的东西,后面我会专门表述一下我的见解tv.setTag(tag);tv.setVisibility(View.VISIBLE);tv.setPressed(false);tv.clearFocus();++index;}}}// 处理没有图标的mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE);// 隐藏其他的图标for (; index < NUM_BUTTONS; ++index) {mIcons[index].setVisibility(View.GONE);}}


4,设置和显示最近的活动对话框。

/** * 设置和显示最近的活动对话框。 */@Overridepublic void onStart() {super.onStart();reloadButtons();//禁止状态栏if (sStatusBar != null) {sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);}// 注册接收广播getContext().registerReceiver(mBroadcastReceiver,mBroadcastIntentFilter);mHandler.removeCallbacks(mCleanup);}


5,处理手指按下的动作

/** * 处理手指按下时的程序 */@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) 


6,处理手指离开的动作

/** * 处理手指抬起时的程序 */@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event)


7,处理用户单击事件

/** * 用户单击处理程序。如果一个按钮被单击时,启动相应的活动。 */@Overridepublic void onClick(View v) {for (TextView b : mIcons) {if (b == v) {RecentTag tag = (RecentTag) b.getTag();switchTo(tag);break;}}dismiss();}


8,切换到所点击的应用

/** * 切换到所点击的应用 *  * @param tag */private void switchTo(RecentTag tag) {if (tag.info.id >= 0) {// 这是一个活跃的任务,所以把它移动到最近任务的前面final ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME);} else if (tag.intent != null) {tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY| Intent.FLAG_ACTIVITY_TASK_ON_HOME);try {getContext().startActivity(tag.intent);} catch (ActivityNotFoundException e) {Log.w("Recent", "Unable to launch recent task", e);}}}


9,处理接收关闭对话框的广播

/** * 这是监听关闭系统对话框意图的广播。收到广播后立即关闭自己,为了允许高优先级的UI来接管(如电话收到了)。 */private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {dismiss();}}}};


如果有需要从别的应用中关闭这个对话框,那么向系统发送一个广播即可:

Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);this.sendBroadcast(i);


更多相关文章

  1. android设置系统图标后手机上不显示出来
  2. 【Android】- Android判断GPS定位是否打开弹出对话框
  3. Android6的Logger日志系统
  4. Android添加自定义系统服务
  5. 通过查看系统的ProgressBar样式来自定义旋转动画
  6. Android中Log系统深究
  7. Android(私有,公有)进程,系统中的进程管理

随机推荐

  1. Android加载html实现文件上传功能
  2. Android之Spinner用法
  3. 理解Android(安卓)UI线程
  4. android 动画2
  5. Android(安卓)P新特性:强制执行 FLAG_ACT
  6. Android登录界面开发及响应;页面跳转;传参
  7. android proguard
  8. android density
  9. Android(安卓)学习记录-调试输出
  10. Android(安卓)Service实现闹钟