android长按home键流程

来源:互联网 发布:mac 磁盘修复 编辑:程序博客网 时间:2024/05/01 13:02


    home键在KeyEvent中的键值为3.

    public static final int KEYCODE_HOME            = 3;

   当用户按下home键的时候(包括长按),程序会进入到PhoneWindowManager.java类中的public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags)这个方法中进行处理。如果用户是连续点击home,此时就要执行长按home事件了。即执行mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());对应的代码。也就会跳转到mHomeLongPress这个Runnable接着往下执行。

   interceptKeyBeforeDispatching这个方法位于PhoneWindowManager.java中。位置为:\frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java  

[java] view plaincopy
  1. public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,  
  2.             int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {  
  3.         final boolean down = (action == KeyEvent.ACTION_DOWN);  
  4.         ...  
  5.         //4、用户按下home,然后马上释放。此时这个条件成立。将之前postDelayed的事件remove掉。此时就不会执行长按home事件。  
  6.         if ((keyCode == KeyEvent.KEYCODE_HOME) && !down) {  
  7.             mHandler.removeCallbacks(mHomeLongPress);  
  8.         }  
  9.         //5、第一次按下home,mHomePressed为false。  
  10.         if (mHomePressed) {  
  11.             if (keyCode == KeyEvent.KEYCODE_HOME) {  
  12.             //a、如果用户连续按下home,此时暂时没有up事件。所以就不走这里。  
  13.             //b、如果用户没有连续按下home,此时过来的是up(move或者...)事件。即!down为true,执行该方法  
  14.                 if (!down) {  
  15.                     mHomePressed = false;  
  16.                     if (!canceled) {  
  17.                         boolean incomingRinging = false;  
  18.                         try {  
  19.                             ITelephony telephonyService = getTelephonyService();  
  20.                             if (telephonyService != null) {  
  21.                                 incomingRinging = telephonyService.isRinging();  
  22.                             }  
  23.                         } catch (RemoteException ex) {  
  24.                             Log.w(TAG, "RemoteException from getPhoneInterface()", ex);  
  25.                         }  
  26.           
  27.                         if (incomingRinging) {  
  28.                             Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");  
  29.                         } else {  
  30.                             //单击home处理  
  31.                             launchHomeFromHotKey();  
  32.                         }  
  33.                     } else {  
  34.                         Log.i(TAG, "Ignoring HOME; event canceled.");  
  35.                     }  
  36.                 }  
  37.             }  
  38.             return true;  
  39.         }  
  40.           
  41.         ...  
  42.           
  43.         //  1、第一次处理home按下  
  44.         if (keyCode == KeyEvent.KEYCODE_HOME) {  
  45.   
  46.             // If a system window has focus, then it doesn't make sense  
  47.             // right now to interact with applications.  
  48.             WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;  
  49.             if (attrs != null) {  
  50.                 final int type = attrs.type;  
  51.                 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD  
  52.                         || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {  
  53.                     // the "app" is keyguard, so give it the key  
  54.                     return false;  
  55.                 }  
  56.                 final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;  
  57.                 for (int i=0; i<typeCount; i++) {  
  58.                     if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {  
  59.                         // don't do anything, but also don't pass it to the app  
  60.                         return true;  
  61.                     }  
  62.                 }  
  63.             }  
  64.             //  2、第一次按下home,会调用postDelayed发送一个延时处理的操作。同时将mHomePressed置为true。  
  65.             // 如果第5 步没有进入if (!down),此时就要执行长按home方法了。  
  66.             if (down && repeatCount == 0) {  
  67.                 if (!keyguardOn) {  
  68.                     mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());  
  69.                 }  
  70.                 mHomePressed = true;  
  71.             }  
  72.             return true;  
  73.         } //其他键的处理  
  74.         else if(...){...}  


mHomeLongPress的代码如下。它的作用是请求生成一个弹出近期任务的对话框。执行showRecentAppsDialog()方法

[java] view plaincopy
  1. /** 
  2.      * When a home-key longpress expires, close other system windows and launch the recent apps 
  3.      */  
  4.     Runnable mHomeLongPress = new Runnable() {  
  5.         public void run() {  
  6.             /* 
  7.              * Eat the longpress so it won't dismiss the recent apps dialog when 
  8.              * the user lets go of the home key 
  9.              */  
  10.             mHomePressed = false;//将mHomePressed还原,就可以接收下次home单击事件了。  
  11.             performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);  
  12.             sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);  
  13.             showRecentAppsDialog();//弹出近期任务的对话框  
  14.         }  
  15.     };  


showRecentAppsDialog()方法如下。它会去创建一个RecentApplicationsDialog对象,从而完成弹出任务对话框的操作。

[java] view plaincopy
  1. /** 
  2.      * Create (if necessary) and launch the recent apps dialog 
  3.      */  
  4.     void showRecentAppsDialog() {  
  5.         if (mRecentAppsDialog == null) {  
  6.             mRecentAppsDialog = new RecentApplicationsDialog(mContext);  
  7.         }  
  8.         mRecentAppsDialog.show();  
  9.     }  

接下来就是创建RecentApplicationsDialog对象来显示近期任务了。该类位置为:\frameworks\base\policy\src\com\android\internal\policy\impl\RecentApplicationsDialog.java

代码中已经做了详细的注解,这里就不再仔细说。最重要的一步就是在onStart()中的reloadButtons()方法。它是获取近期任务的方法。

[java] view plaincopy
  1. public class RecentApplicationsDialog extends Dialog implements OnClickListener {  
  2.     // Elements for debugging support  
  3.     private static final boolean DBG_FORCE_EMPTY_LIST = false;  
  4.     static private StatusBarManager sStatusBar;  
  5.     private static final int NUM_BUTTONS = 8;  
  6.     private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2;    // allow for some discards  
  7.     final TextView[] mIcons = new TextView[NUM_BUTTONS];  
  8.     View mNoAppsText;  
  9.     IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);//广播接收者  
  10.     Handler mHandler = new Handler();  
  11.     //将每个TextView相关的intent信息和drawable信息删除  
  12.     Runnable mCleanup = new Runnable() {  
  13.         public void run() {  
  14.             // dump extra memory we're hanging on to  
  15.             for (TextView icon: mIcons) {  
  16.                 icon.setCompoundDrawables(nullnullnullnull);  
  17.                 icon.setTag(null);  
  18.             }  
  19.         }  
  20.     };  
  21.   
  22.     private int mIconSize;  
  23.   
  24.     public RecentApplicationsDialog(Context context) {  
  25.         super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);  
  26.   
  27.         final Resources resources = context.getResources();  
  28.         mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size);  
  29.     }  
  30.   
  31.     /** 
  32.      * We create the recent applications dialog just once, and it stays around (hidden) 
  33.      * until activated by the user. 
  34.      * 
  35.      * @see PhoneWindowManager#showRecentAppsDialog 
  36.      */  
  37.     @Override  
  38.     protected void onCreate(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.   
  41.         Context context = getContext();  
  42.   
  43.         //StatusBarManager这个系统服务只供系统内部使用,不对外开放。作用是对状态栏进行管理,我们不去管它。  
  44.         //该类位置:\frameworks\base\core\java\android\app\StatusBarManager.java  
  45.         if (sStatusBar == null) {  
  46.             sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);  
  47.         }  
  48.   
  49.         //请求窗口的一些属性  
  50.         Window window = getWindow();  
  51.         window.requestFeature(Window.FEATURE_NO_TITLE);  
  52.         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  
  53.         window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,  
  54.                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);  
  55.         window.setTitle("Recents");  
  56.   
  57.         setContentView(com.android.internal.R.layout.recent_apps_dialog);  
  58.         final WindowManager.LayoutParams params = window.getAttributes();  
  59.         params.width = WindowManager.LayoutParams.MATCH_PARENT;  
  60.         params.height = WindowManager.LayoutParams.MATCH_PARENT;  
  61.         window.setAttributes(params);  
  62.         window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);  
  63.   
  64.         //最多放八个近期任务  
  65.         mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0);  
  66.         mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1);  
  67.         mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2);  
  68.         mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3);  
  69.         mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4);  
  70.         mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5);  
  71.         mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6);  
  72.         mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7);  
  73.         mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);  
  74.   
  75.         //每个近期任务的点击事件监听  
  76.         for (TextView b: mIcons) {  
  77.             b.setOnClickListener(this);  
  78.         }  
  79.     }  
  80.   
  81.     /** 
  82.      * Handler for user clicks.  If a button was clicked, launch the corresponding activity. 
  83.      */  
  84.     public void onClick(View v) {  
  85.   
  86.         for (TextView b: mIcons) {  
  87.             if (b == v) {  
  88.                 // prepare a launch intent and send it  
  89.                 //b.getTag得到从ActivityManager取得的每一个任务的intent信息  
  90.                 Intent intent = (Intent)b.getTag();  
  91.                 if (intent != null) {  
  92.                     intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);  
  93.                     try {  
  94.                         getContext().startActivity(intent);  
  95.                     } catch (ActivityNotFoundException e) {  
  96.                         Log.w("Recent""Unable to launch recent task", e);  
  97.                     }  
  98.                 }  
  99.                 break;  
  100.             }  
  101.         }  
  102.         dismiss();  
  103.     }  
  104.   
  105.     /** 
  106.      * Set up and show the recent activities dialog. 
  107.      显示近期任务对话框 
  108.      */  
  109.     @Override  
  110.     public void onStart() {  
  111.         super.onStart();  
  112.         reloadButtons();  
  113.         if (sStatusBar != null) {  
  114.             sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);  
  115.         }  
  116.   
  117.         // receive broadcasts  
  118.         //注册广播,接收ACTION_CLOSE_SYSTEM_DIALOGS的intent。比如当有电话打过来时,dialog会被让位给打电话的ui  
  119.         getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);  
  120.         mHandler.removeCallbacks(mCleanup);  
  121.     }  
  122.   
  123.     /** 
  124.      * Dismiss the recent activities dialog. 
  125.      */  
  126.     @Override  
  127.     public void onStop() {  
  128.         super.onStop();  
  129.   
  130.         if (sStatusBar != null) {  
  131.             sStatusBar.disable(StatusBarManager.DISABLE_NONE);  
  132.         }  
  133.   
  134.         //  
  135.         // stop receiving broadcasts  
  136.         //接触广播  
  137.         getContext().unregisterReceiver(mBroadcastReceiver);  
  138.   
  139.         mHandler.postDelayed(mCleanup, 100);  
  140.      }  
  141.   
  142.     /** 
  143.      * Reload the 6 buttons with recent activities 
  144.      * 最重要的方法,如何从ActivityManager中获取到近期任务。并将其信息"注入"到每一个icon(TextView)中。 
  145.      */  
  146.     private void reloadButtons() {  
  147.   
  148.         final Context context = getContext();  
  149.         final PackageManager pm = context.getPackageManager();  
  150.         final ActivityManager am = (ActivityManager)  
  151.                 context.getSystemService(Context.ACTIVITY_SERVICE);  
  152.         final List<ActivityManager.RecentTaskInfo> recentTasks =  
  153.                 am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);  
  154.   
  155.         ActivityInfo homeInfo =   
  156.             new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)  
  157.                     .resolveActivityInfo(pm, 0);  
  158.   
  159.         //近期任务中的图片的创建以及它的选中事件等等图标颜色变化之类的处理。可以想象成我们listview中元素创建以及点击状态变化的处理。  
  160.         //该类位置:\frameworks\base\policy\src\com\android\internal\policy\impl\IconUtilities.java  
  161.         IconUtilities iconUtilities = new IconUtilities(getContext());  
  162.   
  163.         // Performance note:  Our android performance guide says to prefer Iterator when  
  164.         // using a List class, but because we know that getRecentTasks() always returns  
  165.         // an ArrayList<>, we'll use a simple index instead.  
  166.         int index = 0;  
  167.         int numTasks = recentTasks.size();  
  168.         //在这里,当前的运行的应用程序一般会第一个加载出来。所以可以在这里将其从近期任务中剔除。方法同剔除  
  169.         //launcher的方法。  
  170.         for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) {  
  171.             final ActivityManager.RecentTaskInfo info = recentTasks.get(i);  
  172.   
  173.             // for debug purposes only, disallow first result to create empty lists  
  174.             if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue;  
  175.   
  176.             Intent intent = new Intent(info.baseIntent);  
  177.             if (info.origActivity != null) {  
  178.                 intent.setComponent(info.origActivity);  
  179.             }  
  180.   
  181.             // Skip the current home activity.  
  182.             //launcher应用程序不需要显示。  
  183.             if (homeInfo != null) {  
  184.                 if (homeInfo.packageName.equals(  
  185.                         intent.getComponent().getPackageName())  
  186.                         && homeInfo.name.equals(  
  187.                                 intent.getComponent().getClassName())) {  
  188.                     continue;  
  189.                 }  
  190.             }  
  191.   
  192.             intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)  
  193.                     | Intent.FLAG_ACTIVITY_NEW_TASK);  
  194.             final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);  
  195.             if (resolveInfo != null) {  
  196.                 final ActivityInfo activityInfo = resolveInfo.activityInfo;  
  197.                 final String title = activityInfo.loadLabel(pm).toString();  
  198.                 Drawable icon = activityInfo.loadIcon(pm);  
  199.   
  200.                 if (title != null && title.length() > 0 && icon != null) {  
  201.                     final TextView tv = mIcons[index];  
  202.                     tv.setText(title);  
  203.                     icon = iconUtilities.createIconDrawable(icon);  
  204.                     tv.setCompoundDrawables(null, icon, nullnull);  
  205.                     tv.setTag(intent);  
  206.                     tv.setVisibility(View.VISIBLE);  
  207.                     tv.setPressed(false);  
  208.                     tv.clearFocus();  
  209.                     ++index;  
  210.                 }  
  211.             }  
  212.         }  
  213.   
  214.         // handle the case of "no icons to show"  
  215.         mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE);  
  216.   
  217.         // hide the rest  
  218.         for (; index < NUM_BUTTONS; ++index) {  
  219.             mIcons[index].setVisibility(View.GONE);  
  220.         }  
  221.     }  
  222.   
  223.     /** 
  224.      * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent.  It's an indication that 
  225.      * we should close ourselves immediately, in order to allow a higher-priority UI to take over 
  226.      * (e.g. phone call received). 
  227.      */  
  228.     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {  
  229.         @Override  
  230.         public void onReceive(Context context, Intent intent) {  
  231.             String action = intent.getAction();  
  232.             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {  
  233.                 String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);  
  234.                 if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {  
  235.                     dismiss();  
  236.                 }  
  237.             }  
  238.         }  
  239.     };  
  240. }  


至此,我们长按home事件的源代码就已经分析完毕。接下来,我们就模拟长按home事件,获取用户近期任务列表。相信有了上面的知识,下面的事情就不是难事了。

二:模拟长按home键弹出近期任务列表

有两个要注意的地方,这里先说出来。

a、final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE)中的ActivityManager.RECENT_IGNORE_UNAVAILABLE这个值不对我们开放,我们可以手动写死。它的值为:0x0002

b、注意加入权限。<uses-permission android:name="android.permission.GET_TASKS"/>

 由于这个工程比较简单,我们只使用了一个MainActivity来实现功能。这里就大概的给童鞋们说一说。具体的可以看demo。

1、在应用程序启动的时候就去执行查找近期任务列表的操作。

[java] view plaincopy
  1. private Dialog mDialog;  
  2. private static int MAX_RECENT_TASKS = 12;    // allow for some discards  
  3. private static int repeatCount = 12;//保证上面两个值相等  
  4. //用来存放每一个recentApplication的信息,我们这里存放应用程序名,应用程序图标和intent。  
  5. private List<HashMap<String,Object>> appInfos = new ArrayList<HashMap<String, Object>>();  
  6.   
  7. @Override  
  8. public void onCreate(Bundle savedInstanceState) {  
  9.     super.onCreate(savedInstanceState);  
  10.     setContentView(R.layout.main);  
  11.     reloadButtons();//程序加载的时候就加载出最近任务  
  12. }  

2reloadButtons()方法的代码如下,获取近期任务代码与源码基本一致,只是在不显示launcher那里做了一些处理。按照下面的代码,如果我们不做处理,我们得到的近期任务列表数据将会少一个。具体看代码中的注释。

[java] view plaincopy
  1. /** 
  2.   * 核心方法,加载最近启动的应用程序 
  3.   * 注意:这里我们取出的最近任务为  MAX_RECENT_TASKS + 1个,因为有可能最近任务中包好Launcher2。 
  4.   * 这样可以保证我们展示出来的  最近任务 为 MAX_RECENT_TASKS 个 
  5.   */  
  6.  private void reloadButtons() {  
  7.        
  8.      //得到包管理器和activity管理器  
  9.      final Context context = this;  
  10.      final PackageManager pm = context.getPackageManager();  
  11.      final ActivityManager am = (ActivityManager)  
  12.              context.getSystemService(Context.ACTIVITY_SERVICE);  
  13.      //从ActivityManager中取出用户最近launch过的 MAX_RECENT_TASKS + 1 个,以从早到晚的时间排序,  
  14.      //注意这个   0x0002,它的值在launcher中是用ActivityManager.RECENT_IGNORE_UNAVAILABLE  
  15.      //但是这是一个隐藏域,因此我把它的值直接拷贝到这里  
  16.      final List<ActivityManager.RecentTaskInfo> recentTasks =  
  17.              am.getRecentTasks(MAX_RECENT_TASKS + 10x0002);  
  18.   
  19.      //这个activity的信息是我们的launcher  
  20.      ActivityInfo homeInfo =   
  21.          new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)  
  22.                  .resolveActivityInfo(pm, 0);  
  23.      int numTasks = recentTasks.size();  
  24.      for (int i = 0; i < numTasks && (i < MAX_RECENT_TASKS); i++) {  
  25.          HashMap<String, Object> singleAppInfo = new HashMap<String, Object>();//当个启动过的应用程序的信息  
  26.          final ActivityManager.RecentTaskInfo info = recentTasks.get(i);  
  27.   
  28.          Intent intent = new Intent(info.baseIntent);  
  29.          if (info.origActivity != null) {  
  30.              intent.setComponent(info.origActivity);  
  31.          }  
  32.          //TODO 测试用,无意义代码  
  33.          String currentInfo = "PackageName==" + intent.getComponent().getPackageName() + ",ClassName==" + intent.getComponent().getClassName();  
  34.          /** 
  35.           * 如果找到是launcher,直接continue,后面的appInfos.add操作就不会发生了 
  36.           */  
  37.          if (homeInfo != null) {  
  38.              if (homeInfo.packageName.equals(  
  39.                      intent.getComponent().getPackageName())  
  40.                      && homeInfo.name.equals(  
  41.                              intent.getComponent().getClassName())) {  
  42.                  MAX_RECENT_TASKS = MAX_RECENT_TASKS + 1;  
  43.                  continue;  
  44.              }  
  45.          }  
  46.   
  47.          //设置intent的启动方式为 创建新task()【并不一定会创建】  
  48.          intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)  
  49.                  | Intent.FLAG_ACTIVITY_NEW_TASK);  
  50.          //获取指定应用程序activity的信息(按我的理解是:某一个应用程序的最后一个在前台出现过的activity。)  
  51.          final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);  
  52.          if (resolveInfo != null) {  
  53.              final ActivityInfo activityInfo = resolveInfo.activityInfo;  
  54.              final String title = activityInfo.loadLabel(pm).toString();  
  55.              Drawable icon = activityInfo.loadIcon(pm);  
  56.   
  57.              if (title != null && title.length() > 0 && icon != null) {  
  58.                  singleAppInfo.put("title", title);  
  59.                  singleAppInfo.put("icon", icon);  
  60.                  singleAppInfo.put("tag", intent);  
  61.              }  
  62.          }  
  63.          appInfos.add(singleAppInfo);  
  64.      }  
  65.      MAX_RECENT_TASKS = repeatCount;  
  66.  }  


3、通过上面的步骤,我们就获得了近期任务列表,并将其存放在了appInfos这个list中,接下来就是展示这个list的工作了。我这里就是简单的弹出一个dialogdialog中放一个gridview。自定义gridview的adapter,在getView方法中进行任务点击事件的处理。代码如下:

MainActivity中的按钮点击事件:

[java] view plaincopy
  1. public void click(View view){  
  2.         int id = view.getId();  
  3.         switch (id) {  
  4.         case R.id.btn:  
  5.             generateDialog();  
  6.             break;  
  7.         }  
  8.     }  
  9.       
  10.     /** 
  11.      * 弹出最近任务对话框 
  12.      */  
  13.     public void generateDialog(){  
  14.         mDialog = new Dialog(this,R.style.dialog);  
  15.         LayoutInflater mInflater = LayoutInflater.from(this);  
  16.         View dialogView = mInflater.inflate(R.layout.choose_dialog, null);  
  17.         final GridView mGridView = (GridView) dialogView.findViewById(R.id.choose_dialog_gridview);  
  18.         mGridView.setAdapter(new MyAppAdapter());  
  19.         mDialog.setContentView(dialogView);  
  20.         mDialog.setCanceledOnTouchOutside(true);  
  21.         mDialog.show();  
  22.     }  

弹出dialog中的gridview适配。

[java] view plaincopy
  1. /** 
  2.      * gridview的适配器 
  3.      * @author yanbin 
  4.      * 
  5.      */  
  6.     private class MyAppAdapter implements ListAdapter{  
  7.   
  8.         @Override  
  9.         public void registerDataSetObserver(DataSetObserver observer) {  
  10.         }  
  11.   
  12.         @Override  
  13.         public void unregisterDataSetObserver(DataSetObserver observer) {  
  14.         }  
  15.   
  16.         @Override  
  17.         public int getCount() {  
  18.             return appInfos.size();  
  19.         }  
  20.   
  21.         @Override  
  22.         public Object getItem(int position) {  
  23.             return appInfos.get(position);  
  24.         }  
  25.   
  26.         @Override  
  27.         public long getItemId(int position) {  
  28.             return position;  
  29.         }  
  30.   
  31.         @Override  
  32.         public boolean hasStableIds() {  
  33.             return false;  
  34.         }  
  35.   
  36.         /** 
  37.          * 自定义view 
  38.          */  
  39.         @Override  
  40.         public View getView(int position, View convertView, ViewGroup parent) {  
  41.             LayoutInflater mInflater = LayoutInflater.from(MainActivity.this);  
  42.             View infoView = mInflater.inflate(R.layout.choose_dialog_detail_info, null);  
  43.             ImageView mImageView = (ImageView) infoView.findViewById(R.id.app_icon);  
  44.             TextView mTextView = (TextView) infoView.findViewById(R.id.choose_dialog_detail_tv);  
  45.             String title = (String) appInfos.get(position).get("title");  
  46.             Drawable icon = (Drawable) appInfos.get(position).get("icon");  
  47.             Intent singleIntent = (Intent) appInfos.get(position).get("tag");  
  48.             infoView.setTag(singleIntent);  
  49.             mImageView.setImageDrawable(icon);  
  50.             mTextView.setText(title);  
  51.             infoView.setOnClickListener(new SingleAppClickListener());  
  52.             return infoView;  
  53.         }  
  54.   
  55.         @Override  
  56.         public int getItemViewType(int position) {  
  57.             return 0;  
  58.         }  
  59.   
  60.         @Override  
  61.         public int getViewTypeCount() {  
  62.             return 1;  
  63.         }  
  64.   
  65.         @Override  
  66.         public boolean isEmpty() {  
  67.             return false;  
  68.         }  
  69.   
  70.         @Override  
  71.         public boolean areAllItemsEnabled() {  
  72.             return false;  
  73.         }  
  74.   
  75.         @Override  
  76.         public boolean isEnabled(int position) {  
  77.             return false;  
  78.         }  
  79.     }  


图标点击事件处理:

[java] view plaincopy
  1. /** 
  2.      * 点击应用图标即可启动程序 
  3.      * @author yanbin 
  4.      * 
  5.      */  
  6.     private class SingleAppClickListener implements View.OnClickListener{  
  7.         @Override  
  8.         public void onClick(View v) {  
  9.             Intent intent = (Intent)v.getTag();  
  10.             if (intent != null) {  
  11.                 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);  
  12.                 try {  
  13.                     MainActivity.this.startActivity(intent);  
  14.                     if(mDialog != null)  
  15.                         mDialog.dismiss();  
  16.                 } catch (ActivityNotFoundException e) {  
  17.                     Log.w("Recent""Unable to launch recent task", e);  
  18.                 }  
  19.             }  
  20.         }  
  21.           
  22.     }  


用到的一些资源文件和布局文件如下:

choose_dialog.xml  对话框。

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical"  
  6.      >  
  7.     <LinearLayout   
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:layout_gravity="center"  
  11.         >  
  12.         <GridView  
  13.         android:id="@+id/choose_dialog_gridview"  
  14.         android:layout_width="wrap_content"  
  15.         android:gravity="center"  
  16.         android:layout_height="wrap_content"  
  17.         android:verticalSpacing="15dp"  
  18.         android:horizontalSpacing="15dp"  
  19.         android:numColumns="3"  
  20.         android:background="@drawable/bg_y"  
  21.         ></GridView>  
  22.     </LinearLayout>  
  23.       
  24.   
  25. </LinearLayout>  


choose_dialog_detail_info.xml   gridview中每一个item的布局。

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:layout_gravity="center"  
  6.      >  
  7.       
  8.     <ImageView   
  9.         android:layout_width="40dp"  
  10.         android:layout_height="40dp"  
  11.         android:src="@drawable/ic_launcher"  
  12.         android:layout_centerInParent="true"  
  13.         android:id="@+id/app_icon"  
  14.         />  
  15.       
  16.     <TextView   
  17.         android:layout_marginTop="20dp"  
  18.         android:layout_below="@+id/app_icon"  
  19.         android:layout_width="wrap_content"  
  20.         android:layout_height="wrap_content"  
  21.         android:singleLine="true"  
  22.         android:background="@null"  
  23.         android:text="cccccccccc"  
  24.         android:layout_centerHorizontal="true"  
  25.         android:id="@+id/choose_dialog_detail_tv"  
  26.         />  
  27.   
  28. </RelativeLayout>  


colors.xml

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   <!-- Copyright (C) 2007 The Android Open Source Project -->  
  3.     
  4. <resources>  
  5.   <color name="transparent">#00000000</color>  
  6. </resources>  

styles.xml

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <style name="dialog" parent="@android:style/Theme.Dialog">  
  4.         <item name="android:windowFrame">@null</item><!--边框-->  
  5.         <item name="android:windowIsFloating">true</item><!--是否浮现在activity之上-->  
  6.         <item name="android:windowIsTranslucent">true</item><!--半透明-->  
  7.         <item name="android:windowNoTitle">true</item><!--无标题-->  
  8.         <item name="android:windowBackground">@color/transparent</item><!--背景透明 -->  
  9.         <item name="android:backgroundDimEnabled">true</item><!--背景暗淡-->  
  10.     </style>      
  11. </resources>  

到这里,我们模拟长按home的代码就全部展示完了。有不足的地方望指正,谢谢。

原创粉丝点击