Android  Launcher全面剖析

            首先来说说我为什么写这篇文章,最近公司要我负责搞Launcher,网上一查这方面的资料比较少,并且不全,研究起来相当困难,所以就写了这篇文章,希望对大家有帮助。这篇文章是相当长的,希望读者能耐心读下去,实际上也花了我很长时间来写。好了闲话少说,我们切入正题。

             这篇文章我会讲以下Launcher内容:

                        Launcher  UI总体架构

                       Launcher   Res下的Layout

                       Launcher   Res下的Xml文件

                       Launcher    Manifest文件

                       Launcher   常用类介绍

                       Launcher    启动过程

                      Launcher    widget添加过程

                       Launcher      celllayout的介绍

                     

一      Launcher  UI总体架构

         

         Home screen可以说是一个手机的最重要应用,就像一个门户网站的首页,直接决定了用户的第一印象。下面对home screen做一简要分析。

home screen的代码位于packages/apps/Launcher目录。从文件launcher.xml,workspace_screen.xml可获知home screen的UI结构如下图所示: 

 

整个homescreen是一个包含三个child view的FrameLayout(com.android.launcher.DragLayer)。

第一个child就是桌面com.android.launcher.Workspace。这个桌面又包含三个child。每个child就对应一个桌面。这就是你在Android上看到的三个桌面。每个桌面上可以放置下列对象:应用快捷方式,appwidget和folder。

第二个child是一个SlidingDrawer控件,这个控件由两个子控件组成。一个是com.android.launcher.HandleView,就是Android桌面下方的把手,当点击这个把手时,另一个子控件,com.android.launcher.AllAppsGridView就会弹出,这个子控件列出系统中当前安装的所有类型为category.launcher的Activity。

第三个child是com.android.launcher.DeleteZone。当用户在桌面上长按一个widget时,把手位置就会出现一个垃圾桶形状的控件,就是这个控件。

在虚拟桌面上可以摆放四种类型的对象:
1. ITEM_SHORTCUT,应用快捷方式
2. ITEM_APPWIDGET,app widget
3. ITEM_LIVE_FOLDER,文件夹
4. ITEM_WALLPAPER,墙纸。

类AddAdapter(AddAdapter.java)列出了这四个类型对象。当用户在桌面空白处长按时,下列函数序列被执行:
Launcher::onLongClick -->
Launcher::showAddDialog -->
Launcher::showDialog(DIALOG_CREATE_SHORTCUT); -->
Launcher::onCreateDialog -->
Launcher::CreateShortcut::createDialog:这个函数创建一个弹出式对话框,询问用户是要添加什么(快捷方式,appwidget, 文件夹和墙纸)其内容就来自AddAdapter。

类Favorites(LauncherSettings.java)和类LauncherProvider定义了一个content provider,用来存储桌面上可以放置的几个对象,包括shortcut, search和clock等。

类DesktopItemsLoader负责将桌面上所有的对象从content provider中提取。

线程private ApplicationsLoader mApplicationsLoader负责从包管理器中获取系统中安装的应用列表。(之后显示在AllAppsGridView上)。ApplicationsLoader::run实现:
1)通过包管理器列出系统中所有类型为Launcher,action为MAIN的activity;
2)对每一个Activity,
      a) 将Activity相关元数据信息,如title, icon, intent等缓存到appInfoCache;
      b) 填充到ApplicationsAdapter 中。填充过程中用到了一些小技巧,每填充4(UI_NOTIFICATION_RATE)个activity更新一下相应view。

在Launcher::onCreate中,函数startLoaders被调用。而该函数接着调用loadApplications和loadUserItems,分别获取系统的应用列表,以及显示在桌面上的对象列表(快捷方式,appwidget,folder等)。

Launcher上排列的所有应用图标由AllAppsGridView对象呈现。这个对象是一个GridView。其对应的Adapter是ApplicationsAdapter,对应的model则是ApplicationInfo数组。数组内容是由ApplicationsLoader装载的。
private class ApplicationsLoader implements Runnable。

 

Launcher中的AndroidManifest.xml可以看出整个Launcher的代码结构。

首先,是一些权限的声明。例如:

view plain copy to clipboard print ?
  1. "android.permission.CALL_PHONE" />  
  2. "android.permission.EXPAND_STATUS_BAR" />  
 

这部分可以略过;

其次,Application的构成,如上图:

 

(1)LauncherHomeScreenActivity

 

view plain copy to clipboard print ?
  1.   
  2.  "android.intent.action.MAIN" />  
  3.  "android.intent.category.HOME"/>  
  4.  "android.intent.category.DEFAULT" />  
  5. "android.intent.category.MONKEY" />   


上面这段代码就标志着它是开机启动后HomeActivity。通过Launcher.javaonCreat()的分析我们可以大致把握屏幕的主要活动:

 

view plain copy to clipboard print ?
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.         super.onCreate(savedInstanceState);  
  3. //把xml文件的内容实例化到View中   
  4.         mInflater = getLayoutInflater();  
  5. //监听应用程序控件改变事件   
  6.         mAppWidgetManager = AppWidgetManager.getInstance(this);  
  7.         mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);  
  8.         mAppWidgetHost.startListening();  
  9. // 用于调试?       
  10.         if (PROFILE_STARTUP) {  
  11.             android.os.Debug.startMethodTracing("/sdcard/launcher");  
  12.         }  
  13.   //监听locale,mcc,mnc是否改变,如果改变,则重写新配置   
  14.       //mcc:mobile country code(国家代码China 460); mnc:mobile network code(网络代码)   
  15.         checkForLocaleChange();  
  16.        /*This allows such applications to have a virtual wallpaper that is larger than the physical screen, matching the size of their workspace.*/  
  17.         setWallpaperDimension();  
  18. //显示主屏幕UI元素,workspace,slidingdrawer(handleview and appgridview),deletezone   
  19.         setContentView(R.layout.launcher);  
  20. //Finds all the views we need and configure them properly.   
  21. //完成workspace,slidingdrawer,deletezone的各种事件操作和监听   
  22.         setupViews();  
  23. //Registers various intent receivers.   
  24. //允许其他应用对本应用的操作   
  25.         registerIntentReceivers();  
  26. //Registers various content observers.   
  27. //例如,注册一个内容观察者跟踪喜爱的应用程序   
  28.         registerContentObservers();  
  29. //重新保存前一个状态(目的??)   
  30.         mSavedState = savedInstanceState;  
  31.         restoreState(mSavedState);  
  32. //调试?   
  33.         if (PROFILE_STARTUP) {  
  34.             android.os.Debug.stopMethodTracing();  
  35.         }  
  36. //Loads the list of installed applications in mApplications.   
  37.         if (!mRestoring) {  
  38.             startLoaders();  
  39.         }  
  40.         // For handling default keys??   
  41.         mDefaultKeySsb = new SpannableStringBuilder();  
  42.         Selection.setSelection(mDefaultKeySsb, 0);  
  43.     }  
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //把xml文件的内容实例化到View中 mInflater = getLayoutInflater(); //监听应用程序控件改变事件 mAppWidgetManager = AppWidgetManager.getInstance(this); mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); // 用于调试? if (PROFILE_STARTUP) { android.os.Debug.startMethodTracing("/sdcard/launcher"); } //监听locale,mcc,mnc是否改变,如果改变,则重写新配置 //mcc:mobile country code(国家代码China 460); mnc:mobile network code(网络代码) checkForLocaleChange(); /*This allows such applications to have a virtual wallpaper that is larger than the physical screen, matching the size of their workspace.*/ setWallpaperDimension(); //显示主屏幕UI元素,workspace,slidingdrawer(handleview and appgridview),deletezone setContentView(R.layout.launcher); //Finds all the views we need and configure them properly. //完成workspace,slidingdrawer,deletezone的各种事件操作和监听 setupViews(); //Registers various intent receivers. //允许其他应用对本应用的操作 registerIntentReceivers(); //Registers various content observers. //例如,注册一个内容观察者跟踪喜爱的应用程序 registerContentObservers(); //重新保存前一个状态(目的??) mSavedState = savedInstanceState; restoreState(mSavedState); //调试? if (PROFILE_STARTUP) { android.os.Debug.stopMethodTracing(); } //Loads the list of installed applications in mApplications. if (!mRestoring) { startLoaders(); } // For handling default keys?? mDefaultKeySsb = new SpannableStringBuilder(); Selection.setSelection(mDefaultKeySsb, 0); } 

方法onActivityResult():完成在workspace上增加shortcutappwidgeLivefolder

方法onSaveInstantceState()onRestoreInstanceState():为了防止SensorLandPort布局自动切换时数据被置空,通过onSaveInstanceState方法可以保存当前窗口的状态,在即将布局切换前将当前的Activity压入历史堆栈。如果我们的Activity在后台没有因为运行内存吃紧被清理,则切换时回触发onRestoreIntanceState()


(2)WallpaperChooser:设置墙纸。

同理我们从onCreat()作为入口来分析这个活动的主要功能。

view plain copy to clipboard print ?
  1. public void onCreate(Bundle icicle) {  
  2.         super.onCreate(icicle);  
  3. //设置允许改变的窗口状态,需在 setContentView 之前调用   
  4.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  5. / /添加墙纸资源,将资源标识符加入到动态数组中  
  6.         findWallpapers();  
  7. //显示墙纸设置屏幕的UI元素,Imageview,Gallery and Button(LinearLayout)   
  8.         setContentView(R.layout.wallpaper_chooser);  
  9. //图片查看功能的实现   
  10.         mGallery = (Gallery) findViewById(R.id.gallery);  
  11.         mGallery.setAdapter(new ImageAdapter(this));  
  12.         mGallery.setOnItemSelectedListener(this);  
  13.         mGallery.setCallbackDuringFling(false);  
  14. //Button事件监听,点击选择setWallpaper(Resid)   
  15.         findViewById(R.id.set).setOnClickListener(this);  
  16.         mImageView = (ImageView) findViewById(R.id.wallpaper);  
  17.     }  
public void onCreate(Bundle icicle) { super.onCreate(icicle); //设置允许改变的窗口状态,需在 setContentView 之前调用 requestWindowFeature(Window.FEATURE_NO_TITLE); / /添加墙纸资源,将资源标识符加入到动态数组中 findWallpapers(); //显示墙纸设置屏幕的UI元素,Imageview,Gallery and Button(LinearLayout) setContentView(R.layout.wallpaper_chooser); //图片查看功能的实现 mGallery = (Gallery) findViewById(R.id.gallery); mGallery.setAdapter(new ImageAdapter(this)); mGallery.setOnItemSelectedListener(this); mGallery.setCallbackDuringFling(false); //Button事件监听,点击选择setWallpaper(Resid) findViewById(R.id.set).setOnClickListener(this); mImageView = (ImageView) findViewById(R.id.wallpaper); } 

 

(3)default_searchable

对于home中任意的Acitivty,使能系统缺省Search模式,这样就可以使用android系统默认的search UI


 

(4)InstallShortcutReceiver

继承自BroadcastReceiver,重写onReceier()方法,对于发送来的Broadcast(这里指Intent)进行过滤(IntentFilt)并且响应(这里是InstallShortcut())。这里分析下onReceive():

view plain copy to clipboard print ?
  1.   
  2.   
  3. public void onReceive(Context context, Intent data) {  
  4.        //接受并过滤Intent   
  5. if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {  
  6.             return;  
  7.         }  
  8.       //获取屏幕   
  9.         int screen = Launcher.getScreen();  
  10. //安装快捷方式   
  11.         if (!installShortcut(context, data, screen)) {  
  12.             //如果屏幕已满,搜寻其他屏幕   
  13.             for (int i = 0; i < Launcher.SCREEN_COUNT; i++) {  
  14.                 if (i != screen && installShortcut(context, data, i)) break;  
  15.             }  
  16.         }  
  17.     }  
public void onReceive(Context context, Intent data) { //接受并过滤Intent if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) { return; } //获取屏幕 int screen = Launcher.getScreen(); //安装快捷方式 if (!installShortcut(context, data, screen)) { //如果屏幕已满,搜寻其他屏幕 for (int i = 0; i < Launcher.SCREEN_COUNT; i++) { if (i != screen && installShortcut(context, data, i)) break; } } } 

其中IntallShortcut()方法:首先,对传入的坐标进行判断(findEmptyCell(),如果是空白位置,则可以放置快捷方式;其次,缺省情况下,我们允许创建重复的快捷方式,具体创建过程(addShortcut())就是把快捷方式的信息传入数据库(addItemToDatabase())。


(5)UninstallShortcutReceiver

同理,UninstallShortcutReceiver()继承自BroadcastReceiver(),实现onReceiver()方法。定义一个ContentResolver对象完成对数据库的访问和操作(通过URI定位),进而删除快捷方式 。


 

(6)LauncherProvider

继承自ContentProvider(),主要是建立一个数据库来存放HomeScreen中的数据信息,并通过内容提供者来实现其他应用对launcher中数据的访问和操作。

重写了ContentProvider()中的方法

getType():返回数据类型。如果有自定义的全新类型,通过此方法完成数据的访问。

query():查询数据。传入URI,返回一个Cursor对象,通过Cursor完成对数据库数据的遍历访问。

Insert():插入一条数据。

bulkInsert():大容量数据的插入。

delete():删除一条数据。

update():更改一条数据。

sendNotify():发送通知。

DatabaseHelper继承自一个封装类SQLiteOpenHelper(),方便了数据库的管理和维护。

重写的方法:

onCreate():创建一个表。其中db.execSQL()方法执行一条SQL语句,通过一条字符串执行相关的操作。当然,对SQL基本语句应该了解。

onUpgrade():升级数据库。

HomeScreen数据库操作的一些方法:

addClockWidget(),addSearchWidget,addShortcut,addAppShortcut,

loadFavorites(),launcherAppWidgetBinder(),convertWidget(),updateContactsShortcuts(),

copyFromCursor()

补充:

AddAdapter(AddAdapter.java)列出了这四个类型对象。当用户在桌面空白处长按时,下列函数序列被执行:

Launcher::onLongClick -->

Launcher::showAddDialog -->

Launcher::showDialog(DIALOG_CREATE_SHORTCUT); -->

Launcher::onCreateDialog -->

Launcher::CreateShortcut::createDialog:这个函数创建一个弹出式对话框,询问用户是要添加什么(快捷方式,appwidget, 文件夹和墙纸)其内容就来自AddAdapter。

DesktopItemsLoader负责将桌面上所有的对象从content provider中提取。

线程private ApplicationsLoader mApplicationsLoader负责从包管理器中获取系统中安装的应用列表。(之后显示在AllAppsGridView上)。ApplicationsLoader::run实现:
1)通过包管理器列出系统中所有类型为Launcher,action为MAIN的activity;
2)对每一个Activity,
       a) 将Activity相关元数据信息,如title, icon, intent等缓存到appInfoCache;
         b) 填充到ApplicationsAdapter 中。填充过程中用到了一些小技巧,每填充4(UI_NOTIFICATION_RATE)个activity更新一下相应view。

在Launcher::onCreate中,函数startLoaders被调用。而该函数接着调用loadApplications和loadUserItems,分别获取系统的应用列表,以及显示在桌面上的对象列表(快捷方式,appwidget,folder等)。
Launcher上排列的所有应用图标由AllAppsGridView对象呈现。这个对象是一个GridView。其对应的Adapter是ApplicationsAdapter,对应的model则是ApplicationInfo数组。数组内容是由ApplicationsLoader装载的。

 

 

二         Launcher   Res下的Layout

 

             现在我们来看res目录里的布局文件,布局文件都放在layout*目录里。
本以为launcher的layout都放在layout目录里,由于屏幕放置方式的不同会对桌面造成一定的影响,所以googleAndroid项目组就决定因地制宜。比如当你横着放置屏幕的时候就会使用layout-land目录里的文件来对系统launcher进行布局,竖着屏幕的时候会使用layout-port内的布局文件来对launcher来布局。
横竖屏幕切换之际,会重新进行布局。那我们就以layout-land目录为例来看吧。
layout-land/launcuer.xml
 

复制到剪贴板  XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>     
  2.      
  3.          
  4.          
  5.     <permission     
  6.         android:name="com.android.zkx_launcher.permission.INSTALL_SHORTCUT"     
  7.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  8.         android:protectionLevel="normal"     
  9.         android:label="@string/permlab_install_shortcut"     
  10.         android:description="@string/permdesc_install_shortcut" />     
  11.     <permission     
  12.         android:name="com.android.zkx_launcher.permission.UNINSTALL_SHORTCUT"     
  13.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  14.         android:protectionLevel="normal"     
  15.         android:label="@string/permlab_uninstall_shortcut"     
  16.         android:description="@string/permdesc_uninstall_shortcut"/>     
  17.     <permission     
  18.         android:name="com.android.zkx_launcher.permission.READ_SETTINGS"     
  19.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  20.         android:protectionLevel="normal"     
  21.         android:label="@string/permlab_read_settings"     
  22.         android:description="@string/permdesc_read_settings"/>     
  23.     <permission     
  24.         android:name="com.android.zkx_launcher.permission.WRITE_SETTINGS"     
  25.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  26.         android:protectionLevel="normal"     
  27.         android:label="@string/permlab_write_settings"     
  28.         android:description="@string/permdesc_write_settings"/>     
  29.      
  30.     <uses-permission android:name="android.permission.CALL_PHONE" />     
  31.     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />     
  32.     <uses-permission android:name="android.permission.GET_TASKS" />     
  33.     <uses-permission android:name="android.permission.READ_CONTACTS"/>     
  34.     <uses-permission android:name="android.permission.SET_WALLPAPER" />     
  35.     <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />     
  36.     <uses-permission android:name="android.permission.VIBRATE" />     
  37.     <uses-permission android:name="android.permission.WRITE_SETTINGS" />     
  38.     <uses-permission android:name="android.permission.BIND_APPWIDGET" />     
  39.     <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />     
  40.     <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />     
  41.          
  42.     <application     
  43.         android:name="LauncherApplication"     
  44.         android:process="@string/process"     
  45.         android:label="@string/application_name"     
  46.         android:icon="@drawable/ic_launcher_home">     
  47.              
  48.         <activity     
  49.             android:name="Launcher"     
  50.             android:launchMode="singleTask"     
  51.             android:clearTaskOnLaunch="true"     
  52.             android:stateNotNeeded="true"     
  53.             android:theme="@style/Theme"     
  54.             android:screenOrientation="nosensor"     
  55.             android:windowSoftInputMode="stateUnspecified|adjustPan">     
  56.             <intent-filter>     
  57.                 <action android:name="android.intent.action.MAIN" />     
  58.                 <category android:name="android.intent.category.HOME" />     
  59.                 <category android:name="android.intent.category.DEFAULT" />     
  60.                 <category android:name="android.intent.category.MONKEY"/>     
  61.             intent-filter>     
  62.         activity>     
  63.              
  64.              
  65.         <activity     
  66.             android:name="WallpaperChooser"     
  67.             android:label="@string/pick_wallpaper"     
  68.             android:icon="@drawable/ic_launcher_wallpaper"     
  69.             android:screenOrientation="nosensor"     
  70.             android:finishOnCloseSystemDialogs="true">     
  71.             <intent-filter>     
  72.                 <action android:name="android.intent.action.SET_WALLPAPER" />     
  73.                 <category android:name="android.intent.category.DEFAULT" />     
  74.             intent-filter>     
  75.         activity>     
  76.      
  77.              
  78.              
  79.         <receiver     
  80.             android:name="InstallShortcutReceiver"     
  81.             android:permission="com.android.zkx_launcher.permission.INSTALL_SHORTCUT">     
  82.             <intent-filter>     
  83.                 <action android:name="com.android.zkx_launcher.action.INSTALL_SHORTCUT" />     
  84.             intent-filter>     
  85.         receiver>     
  86.      
  87.              
  88.              
  89.         <receiver     
  90.             android:name="UninstallShortcutReceiver"     
  91.             android:permission="com.android.zkx_launcher.permission.UNINSTALL_SHORTCUT">     
  92.             <intent-filter>     
  93.                 <action android:name="com.android.zkx_launcher.action.UNINSTALL_SHORTCUT" />     
  94.             intent-filter>     
  95.         receiver>     
  96.      
  97.              
  98.              
  99.         <provider     
  100.             android:name="LauncherProvider"     
  101.             android:authorities="com.android.zkx_launcher.settings"     
  102.             android:writePermission="com.android.zkx_launcher.permission.WRITE_SETTINGS"     
  103.             android:readPermission="com.android.zkx_launcher.permission.READ_SETTINGS" />     
  104.     application>     
  105. manifest>    

三         Launcher   Res下的Xml文件

           

            Res/xml下有两个xml文件,default_workspace.xml&&default_wallpaper.xml  

             Andorid这个默认壁纸不在launcher里,在源码中frameworks/base/core/res/res /drawable/default_wallpaper.jpg.
frameworks/base/core/res/res路径下包含很多default资源。如果需要修改默认设置可以尝试到这里来找一找

   

   
            launcher:packageName="com.google.android.apps.genie.geniewidget"
        launcher:className="com.google.android.apps.genie.geniewidget.miniwidget.MiniWidgetProvider"
        launcher:screen="1"
        launcher:x="0"
        launcher:y="0"
        launcher:spanX="4"
        launcher:spanY="1" />
#天气新闻时钟插件
#packageName:widgetpackageName
#className :实现 widget receiver 类的名称.
#launcher:container 放置的位 置(只能为desktop
#screen : 在哪一个screen添加

#x,y: 在screen中的位置

#launcher:spanX:在x方向上所占格数
#launcher:spanY:在y方向上所占格数

        
   
            launcher:screen="2"
        launcher:x="0"
        launcher:y="0" />

 
            launcher:packageName="com.android.protips"
        launcher:className="com.android.protips.ProtipWidget"
        launcher:screen="2"
        launcher:x="0"
        launcher:y="1"
        launcher:spanX="4"
        launcher:spanY="1 " />


   
            launcher:packageName="com.android.music"
        launcher:className="com.android.music.MediaAppWidgetProvider"
        launcher:screen="3"
        launcher:x="0"
        launcher:y="0"
        launcher:spanX="4"
        launcher:spanY="1" />

 
            launcher:packageName="com.android.vending"
        launcher:className="com.android.vending.MarketWidgetProvider"
        launcher:screen="3"
        launcher:x="1"
        launcher:y="1"
        launcher:spanX="2"
        launcher:spanY="2" />
#电子市场Android Market
   

 

    四         Launcher    Manifest文件               Launcher的AndroidManifest.xml文件有很多特殊性,分析一下就会理解整个程序的大概结构。
代码如下:

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

  package="net.sunniwell.launcher"

  android:versionCode="1"android:versionName="1.0.1">

关于自定义权限,这是很好的例子,其他apk程序要想使用Launcher的功能必须添加这些权限,而这些权限都是在这里声明的。


这个是安装快捷方式的权限定义:


<permission

      android:name="com.android.launcher.permission.INSTALL_SHORTCUT"

      android:permissionGroup="android.permission-group.SYSTEM_TOOLS"

      android:protectionLevel="normal"

      android:label="@string/permlab_install_shortcut"

      android:description="@string/permdesc_install_shortcut"/>



这个是卸载快捷方式的权限定义:


<permission

      android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"

      android:permissionGroup="android.permission-group.SYSTEM_TOOLS"

      android:protectionLevel="normal"

      android:label="@string/permlab_uninstall_shortcut"

      android:description="@string/permdesc_uninstall_shortcut"/>


这个是读取launcher.db内容的权限定义:


<permission

      android:name="net.sunniwell.launcher.permission.READ_SETTINGS"

      android:permissionGroup="android.permission-group.SYSTEM_TOOLS"

      android:protectionLevel="normal"

      android:label="@string/permlab_read_settings"

      android:description="@string/permdesc_read_settings"/>


这个是修改和删除launcher.db内容的权限定义:


<permission

      android:name="net.sunniwell.launcher.permission.WRITE_SETTINGS"

      android:permissionGroup="android.permission-group.SYSTEM_TOOLS"

      android:protectionLevel="normal"

      android:label="@string/permlab_write_settings"

      android:description="@string/permdesc_write_settings"/>

这些是Launcher的权限声明,通过这些就能看出launcher的大概功能了:

打电话权限:


<uses-permissionandroid:name="android.permission.CALL_PHONE"/>

使用状态栏权限:


<uses-permissionandroid:name="android.permission.EXPAND_STATUS_BAR"/>

获取当前或最近运行的任务的信息的权限:


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

读取通信录权限:


<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>

设置壁纸权限:

<uses-permissionandroid:name="android.permission.SET_WALLPAPER"/>

允许程序设置壁纸hits的权限:

<uses-permissionandroid:name="android.permission.SET_WALLPAPER_HINTS"/>

 

使用震动功能权限:

<uses-permissionandroid:name="android.permission.VIBRATE"/>

修改删除launcher.db内容权限:

<uses-permissionandroid:name="android.permission.WRITE_SETTINGS"/>

绑定widget权限:

<uses-permissionandroid:name="android.permission.BIND_APPWIDGET"/>

读取launcher.db内容权限:

<uses-permissionandroid:name="net.sunniwell.launcher.permission.READ_SETTINGS"/>

修改删除launcher.db内容权限:

<uses-permissionandroid:name="net.sunniwell.launcher.permission.WRITE_SETTINGS"/>

读写外部存储设备权限:

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE">uses-permission>




<application

      android:name="LauncherApplication"

  activity应该运行的进程的名字:

android:process="android.process.acore"

      android:label="@string/application_name"

      android:icon="@drawable/swicon">


<activity

        android:name="Launcher"

         是否

android:launchMode="singleTask"

        android:clearTaskOnLaunch="true"

        这个activity是否在被杀死或者重启后能恢复原来的状态:

android:stateNotNeeded="true"

        android:theme="@style/Theme"

        android:screenOrientation="landscape"

        android:windowSoftInputMode="stateUnspecified|adjustPan">


<intent-filter>


<actionandroid:name="android.intent.action.MAIN"/>


<categoryandroid:name="android.intent.category.LAUNCHER"/>



桌面应用的标记:

<categoryandroid:name="android.intent.category.HOME"/>


<categoryandroid:name="android.intent.category.DEFAULT"/>


自动化测试工具Monkey的标记,待研究

<categoryandroid:name="android.intent.category.MONKEY"/>



intent-filter>


activity>

选择壁纸的activity:

<activity

        android:name="WallpaperChooser"

        android:label="@string/pick_wallpaper"

        android:icon="@drawable/ic_launcher_gallery">


设置壁纸的intent-filter


<intent-filter>


<actionandroid:name="android.intent.action.SET_WALLPAPER"/>


<categoryandroid:name="android.intent.category.DEFAULT"/>


intent-filter>

搜索的activity

activity>



<meta-data

        android:name="android.app.default_searchable"

        android:value="*"/>

安装快捷方式的广播接收器:




<receiver

        android:name=".InstallShortcutReceiver"

        android:permission="com.android.launcher.permission.INSTALL_SHORTCUT">


<intent-filter>


<actionandroid:name="com.android.launcher.action.INSTALL_SHORTCUT"/>


intent-filter>


receiver>


卸载快捷方式的广播接收器:


<receiver

        android:name=".UninstallShortcutReceiver"

        android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT">


<intent-filter>


<actionandroid:name="com.android.launcher.action.UNINSTALL_SHORTCUT"/>


intent-filter>


receiver>

声明ContentProvider,用于对launcher.db操作:



<provider

        android:name="SWLauncherProvider"

        android:authorities="net.sunniwell.launcher.settings"

        android:writePermission="net.sunniwell.launcher.permission.WRITE_SETTINGS"

        android:readPermission="net.sunniwell.launcher.permission.READ_SETTINGS"/>


application>


<uses-sdkandroid:minSdkVersion="4"/>

manifest>
说明:
1.
标签头部还应声明:
android:sharedUserId="android.uid.shared",作用是获得系统权限,但是这样的程序属性只能在build整个系统时放进去(就是系统软件)才起作用,手动安装是没有权限的。

  五          Launcher   常用类介绍                 

AddAdapter: 维护了 live fold  , widget , shortcut , wallpaper 4 个 ListItem , 长按桌面会显示该列表

AllAppsGridView :显示 APP 的网格

ApplicationInfo :一个可启动的应用

ApplicationsAdapter : gridview 的 adapter

BubbleTextView: 一个定制了的 textview

CellLayout: 屏幕网格化

DeleteZone : UI 的一部分

DragController , dragscroller, dragsource, droptarget: 支持拖拽操作

DragLayer :内部支持拖拽的 viewgroup

FastBitmapDrawable :工具

Folder : Icons 的集合

FolderIcon: 出现在 workspace 的 icon 代表了一个 folder

FolderInfo: ItemInfo 子类

HandleView :一个 imageview 。

InstallShortcutReceiver , UninstallShortcutReceiver :一个 broadcastrecier

ItemInfo: 代表 Launcher 中一个 Item (例如 folder )

Launcher: Launcher 程序的主窗口

LauncherApplication :在 VM 中设置参数

LauncherAppWidgetHost , LauncherAppWidgetHostView ,: Widget 相关

LauncherModel : MVC 中的 M

LauncherProvider :一个 contentprovider ,为 Launcher 存储信息

LauncherSettings: 设置相关的工具

LiveFolder , LiveFolderAdapter , LiveFolderIcon , LiveFolderInfo : livefolder 相关

Search : 搜索

UserFolder , UserFolderInfo :文件夹包含 applications ,shortcuts

Utilities: 小工具

WallpaperChooser :选择 wallpaper 的 activity

Workspace: 屏幕上的一块区域

widget : 代表启动的 widget 实例,例如搜索

总结

1) Launcher中实现了MVC模式(M:launchermode , V:draglayer ,C: launcher),以此为主线,可以得到 Launcher对各个组件管理的细节(如drag的实现)。

 

 

 

六     Launcher   起动过程

 

                 Android系统在启动时会安装应用程序,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应用程序就是Launcher了,我将详细分析Launcher应用程序的启动过程。

        Android系统的Home应用程序Launcher是由ActivityManagerService启动的,而ActivityManagerService和PackageManagerService一样,都是在开机时由SystemServer组件启动的,SystemServer组件首先是启动ePackageManagerServic,由它来负责安装系统的应用程序,系统中的应用程序安装好了以后,SystemServer组件接下来就要通过ActivityManagerService来启动Home应用程序Launcher了,Launcher在启动的时候便会通过PackageManagerServic把系统中已经安装好的应用程序以快捷图标的形式展示在桌面上,这样用户就可以使用这些应用程序了。

              下面详细分析每一个步骤。

        Step 1. SystemServer.main

             这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

view plain copy to clipboard print ?
  1. public class SystemServer  
  2. {  
  3.     ......  
  4.   
  5.     native public static void init1(String[] args);  
  6.   
  7.     ......  
  8.   
  9.     public static void main(String[] args) {  
  10.         ......  
  11.   
  12.         init1(args);  
  13.   
  14.         ......  
  15.     }  
  16.   
  17.     ......  
  18. }  
public class SystemServer { ...... native public static void init1(String[] args); ...... public static void main(String[] args) { ...... init1(args); ...... } ...... }        SystemServer组件是由Zygote进程负责启动的,启动的时候就会调用它的main函数,这个函数主要调用了JNI方法init1来做一些系统初始化的工作。

        Step 2. SystemServer.init1

        这个函数是一个JNI方法,实现在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:

view plain copy to clipboard print ?
  1. namespace android {  
  2.   
  3. extern "C" int system_init();  
  4.   
  5. static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)  
  6. {  
  7.     system_init();  
  8. }  
  9.   
  10. /* 
  11.  * JNI registration. 
  12.  */  
  13. static JNINativeMethod gMethods[] = {  
  14.     /* name, signature, funcPtr */  
  15.     { "init1""([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },  
  16. };  
  17.   
  18. int register_android_server_SystemServer(JNIEnv* env)  
  19. {  
  20.     return jniRegisterNativeMethods(env, "com/android/server/SystemServer",  
  21.             gMethods, NELEM(gMethods));  
  22. }  
  23.   
  24. }; // namespace android  
namespace android { extern "C" int system_init(); static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) { system_init(); } /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 }, }; int register_android_server_SystemServer(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/SystemServer", gMethods, NELEM(gMethods)); } }; // namespace android         这个函数很简单,只是调用了system_init函数来进一步执行操作。

        Step 3. libsystem_server.system_init

        函数system_init实现在libsystem_server库中,源代码位于frameworks/base/cmds/system_server/library/system_init.cpp文件中:

view plain copy to clipboard print ?
  1. extern "C" status_t system_init()  
  2. {  
  3.     LOGI("Entered system_init()");  
  4.   
  5.     sp proc(ProcessState::self());  
  6.   
  7.     sp sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp grim = new GrimReaper();  
  11.     sm->asBinder()->linkToDeath(grim, grim.get(), 0);  
  12.   
  13.     char propBuf[PROPERTY_VALUE_MAX];  
  14.     property_get("system_init.startsurfaceflinger", propBuf, "1");  
  15.     if (strcmp(propBuf, "1") == 0) {  
  16.         // Start the SurfaceFlinger   
  17.         SurfaceFlinger::instantiate();  
  18.     }  
  19.   
  20.     // Start the sensor service   
  21.     SensorService::instantiate();  
  22.   
  23.     // On the simulator, audioflinger et al don't get started the   
  24.     // same way as on the device, and we need to start them here   
  25.     if (!proc->supportsProcesses()) {  
  26.   
  27.         // Start the AudioFlinger   
  28.         AudioFlinger::instantiate();  
  29.   
  30.         // Start the media playback service   
  31.         MediaPlayerService::instantiate();  
  32.   
  33.         // Start the camera service   
  34.         CameraService::instantiate();  
  35.   
  36.         // Start the audio policy service   
  37.         AudioPolicyService::instantiate();  
  38.     }  
  39.   
  40.     // And now start the Android runtime.  We have to do this bit   
  41.     // of nastiness because the Android runtime initialization requires   
  42.     // some of the core system services to already be started.   
  43.     // All other servers should just start the Android runtime at   
  44.     // the beginning of their processes's main(), before calling   
  45.     // the init function.   
  46.     LOGI("System server: starting Android runtime.\n");  
  47.   
  48.     AndroidRuntime* runtime = AndroidRuntime::getRuntime();  
  49.   
  50.     LOGI("System server: starting Android services.\n");  
  51.     runtime->callStatic("com/android/server/SystemServer""init2");  
  52.   
  53.     // If running in our own process, just go into the thread   
  54.     // pool.  Otherwise, call the initialization finished   
  55.     // func to let this process continue its initilization.   
  56.     if (proc->supportsProcesses()) {  
  57.         LOGI("System server: entering thread pool.\n");  
  58.         ProcessState::self()->startThreadPool();  
  59.         IPCThreadState::self()->joinThreadPool();  
  60.         LOGI("System server: exiting thread pool.\n");  
  61.     }  
  62.   
  63.     return NO_ERROR;  
  64. }  
extern "C" status_t system_init() { LOGI("Entered system_init()"); sp proc(ProcessState::self()); sp sm = defaultServiceManager(); LOGI("ServiceManager: %p\n", sm.get()); sp grim = new GrimReaper(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsurfaceflinger", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the SurfaceFlinger SurfaceFlinger::instantiate(); } // Start the sensor service SensorService::instantiate(); // On the simulator, audioflinger et al don't get started the // same way as on the device, and we need to start them here if (!proc->supportsProcesses()) { // Start the AudioFlinger AudioFlinger::instantiate(); // Start the media playback service MediaPlayerService::instantiate(); // Start the camera service CameraService::instantiate(); // Start the audio policy service AudioPolicyService::instantiate(); } // And now start the Android runtime. We have to do this bit // of nastiness because the Android runtime initialization requires // some of the core system services to already be started. // All other servers should just start the Android runtime at // the beginning of their processes's main(), before calling // the init function. LOGI("System server: starting Android runtime.\n"); AndroidRuntime* runtime = AndroidRuntime::getRuntime(); LOGI("System server: starting Android services.\n"); runtime->callStatic("com/android/server/SystemServer", "init2"); // If running in our own process, just go into the thread // pool. Otherwise, call the initialization finished // func to let this process continue its initilization. if (proc->supportsProcesses()) { LOGI("System server: entering thread pool.\n"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOGI("System server: exiting thread pool.\n"); } return NO_ERROR; }        这个函数首先会初始化SurfaceFlinger、SensorService、AudioFlinger、MediaPlayerService、CameraService和AudioPolicyService这几个服务,然后就通过系统全局唯一的AndroidRuntime实例变量runtime的callStatic来调用SystemServer的init2函数了。关于这个AndroidRuntime实例变量runtime的相关资料,可能参考前面一篇文章 Android应用程序进程启动过程的源代码分析一文。

        Step 4. AndroidRuntime.callStatic

        这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

view plain copy to clipboard print ?
  1. /* 
  2. * Call a static Java Programming Language function that takes no arguments and returns void. 
  3. */  
  4. status_t AndroidRuntime::callStatic(const char* className, const char* methodName)  
  5. {  
  6.     JNIEnv* env;  
  7.     jclass clazz;  
  8.     jmethodID methodId;  
  9.   
  10.     env = getJNIEnv();  
  11.     if (env == NULL)  
  12.         return UNKNOWN_ERROR;  
  13.   
  14.     clazz = findClass(env, className);  
  15.     if (clazz == NULL) {  
  16.         LOGE("ERROR: could not find class '%s'\n", className);  
  17.         return UNKNOWN_ERROR;  
  18.     }  
  19.     methodId = env->GetStaticMethodID(clazz, methodName, "()V");  
  20.     if (methodId == NULL) {  
  21.         LOGE("ERROR: could not find method %s.%s\n", className, methodName);  
  22.         return UNKNOWN_ERROR;  
  23.     }  
  24.   
  25.     env->CallStaticVoidMethod(clazz, methodId);  
  26.   
  27.     return NO_ERROR;  
  28. }  
/* * Call a static Java Programming Language function that takes no arguments and returns void. */ status_t AndroidRuntime::callStatic(const char* className, const char* methodName) { JNIEnv* env; jclass clazz; jmethodID methodId; env = getJNIEnv(); if (env == NULL) return UNKNOWN_ERROR; clazz = findClass(env, className); if (clazz == NULL) { LOGE("ERROR: could not find class '%s'\n", className); return UNKNOWN_ERROR; } methodId = env->GetStaticMethodID(clazz, methodName, "()V"); if (methodId == NULL) { LOGE("ERROR: could not find method %s.%s\n", className, methodName); return UNKNOWN_ERROR; } env->CallStaticVoidMethod(clazz, methodId); return NO_ERROR; }        这个函数调用由参数className指定的java类的静态成员函数,这个静态成员函数是由参数methodName指定的。上面传进来的参数className的值为"com/android/server/SystemServer",而参数methodName的值为"init2",因此,接下来就会调用SystemServer类的init2函数了。

        Step 5. SystemServer.init2

        这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

view plain copy to clipboard print ?
  1. public class SystemServer  
  2. {  
  3.     ......  
  4.   
  5.     public static final void init2() {  
  6.         Slog.i(TAG, "Entered the Android system server!");  
  7.         Thread thr = new ServerThread();  
  8.         thr.setName("android.server.ServerThread");  
  9.         thr.start();  
  10.     }  
  11. }  
public class SystemServer { ...... public static final void init2() { Slog.i(TAG, "Entered the Android system server!"); Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); } }        这个函数创建了一个ServerThread线程,PackageManagerService服务就是这个线程中启动的了。这里调用了ServerThread实例thr的start函数之后,下面就会执行这个实例的run函数了。

        Step 6. ServerThread.run

        这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

view plain copy to clipboard print ?
  1. class ServerThread extends Thread {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public void run() {  
  6.         ......  
  7.   
  8.         IPackageManager pm = null;  
  9.   
  10.         ......  
  11.   
  12.         // Critical services...   
  13.         try {  
  14.             ......  
  15.   
  16.             Slog.i(TAG, "Package Manager");  
  17.             pm = PackageManagerService.main(context,  
  18.                         factoryTest != SystemServer.FACTORY_TEST_OFF);  
  19.   
  20.             ......  
  21.         } catch (RuntimeException e) {  
  22.             Slog.e("System""Failure starting core service", e);  
  23.         }  
  24.   
  25.         ......  
  26.     }  
  27.   
  28.     ......  
  29. }  
class ServerThread extends Thread { ...... @Override public void run() { ...... IPackageManager pm = null; ...... // Critical services... try { ...... Slog.i(TAG, "Package Manager"); pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF); ...... } catch (RuntimeException e) { Slog.e("System", "Failure starting core service", e); } ...... } ...... }        这个函数除了启动PackageManagerService服务之外,还启动了其它很多的服务,例如在前面学习Activity和Service的几篇文章中经常看到的ActivityManagerService服务,有兴趣的读者可以自己研究一下。    Step 7. ActivityManagerService.main

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:

view plain copy to clipboard print ?
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     public static final Context main(int factoryTest) {  
  6.         AThread thr = new AThread();  
  7.         thr.start();  
  8.   
  9.         synchronized (thr) {  
  10.             while (thr.mService == null) {  
  11.                 try {  
  12.                     thr.wait();  
  13.                 } catch (InterruptedException e) {  
  14.                 }  
  15.             }  
  16.         }  
  17.   
  18.         ActivityManagerService m = thr.mService;  
  19.         mSelf = m;  
  20.         ActivityThread at = ActivityThread.systemMain();  
  21.         mSystemThread = at;  
  22.         Context context = at.getSystemContext();  
  23.         m.mContext = context;  
  24.         m.mFactoryTest = factoryTest;  
  25.         m.mMainStack = new ActivityStack(m, context, true);  
  26.   
  27.         m.mBatteryStatsService.publish(context);  
  28.         m.mUsageStatsService.publish(context);  
  29.   
  30.         synchronized (thr) {  
  31.             thr.mReady = true;  
  32.             thr.notifyAll();  
  33.         }  
  34.   
  35.         m.startRunning(nullnullnullnull);  
  36.   
  37.         return context;  
  38.     }  
  39.   
  40.     ......  
  41. }  
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public static final Context main(int factoryTest) { AThread thr = new AThread(); thr.start(); synchronized (thr) { while (thr.mService == null) { try { thr.wait(); } catch (InterruptedException e) { } } } ActivityManagerService m = thr.mService; mSelf = m; ActivityThread at = ActivityThread.systemMain(); mSystemThread = at; Context context = at.getSystemContext(); m.mContext = context; m.mFactoryTest = factoryTest; m.mMainStack = new ActivityStack(m, context, true); m.mBatteryStatsService.publish(context); m.mUsageStatsService.publish(context); synchronized (thr) { thr.mReady = true; thr.notifyAll(); } m.startRunning(null, null, null, null); return context; } ...... }        这个函数首先通过AThread线程对象来内部创建了一个ActivityManagerService实例,然后将这个实例保存其成员变量mService中,接着又把这个ActivityManagerService实例保存在ActivityManagerService类的静态成员变量mSelf中,最后初始化其它成员变量,就结束了。

        Step 8. PackageManagerService.main

这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

view plain copy to clipboard print ?
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public static final IPackageManager main(Context context, boolean factoryTest) {  
  5.         PackageManagerService m = new PackageManagerService(context, factoryTest);  
  6.         ServiceManager.addService("package", m);  
  7.         return m;  
  8.     }  
  9.   
  10.     ......  
  11. }  
class PackageManagerService extends IPackageManager.Stub { ...... public static final IPackageManager main(Context context, boolean factoryTest) { PackageManagerService m = new PackageManagerService(context, factoryTest); ServiceManager.addService("package", m); return m; } ...... }        这个函数创建了一个PackageManagerService服务实例,然后把这个服务添加到ServiceManager中去,ServiceManager是Android系统Binder进程间通信机制的守护进程,负责管理系统中的Binder对象,在创建这个PackageManagerService服务实例时,会在PackageManagerService类的构造函数中开始执行安装应用程序的过程:

view plain copy to clipboard print ?
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public PackageManagerService(Context context, boolean factoryTest) {  
  5.         ......  
  6.   
  7.         synchronized (mInstallLock) {  
  8.             synchronized (mPackages) {  
  9.                 ......  
  10.   
  11.                 File dataDir = Environment.getDataDirectory();  
  12.                 mAppDataDir = new File(dataDir, "data");  
  13.                 mSecureAppDataDir = new File(dataDir, "secure/data");  
  14.                 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
  15.   
  16.                 ......  
  17.   
  18.                 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");  
  19.                 mDalvikCacheDir = new File(dataDir, "dalvik-cache");  
  20.   
  21.                 ......  
  22.   
  23.                 // Find base frameworks (resource packages without code).   
  24.                 mFrameworkInstallObserver = new AppDirObserver(  
  25.                 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);  
  26.                 mFrameworkInstallObserver.startWatching();  
  27.                 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM  
  28.                     | PackageParser.PARSE_IS_SYSTEM_DIR,  
  29.                     scanMode | SCAN_NO_DEX, 0);  
  30.   
  31.                 // Collect all system packages.   
  32.                 mSystemAppDir = new File(Environment.getRootDirectory(), "app");  
  33.                 mSystemInstallObserver = new AppDirObserver(  
  34.                     mSystemAppDir.getPath(), OBSERVER_EVENTS, true);  
  35.                 mSystemInstallObserver.startWatching();  
  36.                 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM  
  37.                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  38.   
  39.                 // Collect all vendor packages.   
  40.                 mVendorAppDir = new File("/vendor/app");  
  41.                 mVendorInstallObserver = new AppDirObserver(  
  42.                     mVendorAppDir.getPath(), OBSERVER_EVENTS, true);  
  43.                 mVendorInstallObserver.startWatching();  
  44.                 scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM  
  45.                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  46.   
  47.   
  48.                 mAppInstallObserver = new AppDirObserver(  
  49.                     mAppInstallDir.getPath(), OBSERVER_EVENTS, false);  
  50.                 mAppInstallObserver.startWatching();  
  51.                 scanDirLI(mAppInstallDir, 0, scanMode, 0);  
  52.   
  53.                 mDrmAppInstallObserver = new AppDirObserver(  
  54.                     mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);  
  55.                 mDrmAppInstallObserver.startWatching();  
  56.                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,  
  57.                     scanMode, 0);  
  58.   
  59.                 ......  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64.     ......  
  65. }  
class PackageManagerService extends IPackageManager.Stub { ...... public PackageManagerService(Context context, boolean factoryTest) { ...... synchronized (mInstallLock) { synchronized (mPackages) { ...... File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); mSecureAppDataDir = new File(dataDir, "secure/data"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); ...... mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); mDalvikCacheDir = new File(dataDir, "dalvik-cache"); ...... // Find base frameworks (resource packages without code). mFrameworkInstallObserver = new AppDirObserver( mFrameworkDir.getPath(), OBSERVER_EVENTS, true); mFrameworkInstallObserver.startWatching(); scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX, 0); // Collect all system packages. mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching(); scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all vendor packages. mVendorAppDir = new File("/vendor/app"); mVendorInstallObserver = new AppDirObserver( mVendorAppDir.getPath(), OBSERVER_EVENTS, true); mVendorInstallObserver.startWatching(); scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false); mAppInstallObserver.startWatching(); scanDirLI(mAppInstallDir, 0, scanMode, 0); mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); mDrmAppInstallObserver.startWatching(); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); ...... } } } ...... }        这里会调用scanDirLI函数来扫描移动设备上的下面这五个目录中的Apk文件:

        /system/framework

        /system/app

        /vendor/app

        /data/app

        /data/app-private

 

Step 9. ActivityManagerService.setSystemProcess

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:

view plain copy to clipboard print ?
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     public static void setSystemProcess() {  
  6.         try {  
  7.             ActivityManagerService m = mSelf;  
  8.   
  9.             ServiceManager.addService("activity", m);  
  10.             ServiceManager.addService("meminfo"new MemBinder(m));  
  11.             if (MONITOR_CPU_USAGE) {  
  12.                 ServiceManager.addService("cpuinfo"new CpuBinder(m));  
  13.             }  
  14.             ServiceManager.addService("permission"new PermissionController(m));  
  15.   
  16.             ApplicationInfo info =  
  17.                 mSelf.mContext.getPackageManager().getApplicationInfo(  
  18.                 "android", STOCK_PM_FLAGS);  
  19.             mSystemThread.installSystemApplicationInfo(info);  
  20.   
  21.             synchronized (mSelf) {  
  22.                 ProcessRecord app = mSelf.newProcessRecordLocked(  
  23.                     mSystemThread.getApplicationThread(), info,  
  24.                     info.processName);  
  25.                 app.persistent = true;  
  26.                 app.pid = MY_PID;  
  27.                 app.maxAdj = SYSTEM_ADJ;  
  28.                 mSelf.mProcessNames.put(app.processName, app.info.uid, app);  
  29.                 synchronized (mSelf.mPidsSelfLocked) {  
  30.                     mSelf.mPidsSelfLocked.put(app.pid, app);  
  31.                 }  
  32.                 mSelf.updateLruProcessLocked(app, truetrue);  
  33.             }  
  34.         } catch (PackageManager.NameNotFoundException e) {  
  35.             throw new RuntimeException(  
  36.                 "Unable to find android system package", e);  
  37.         }  
  38.     }  
  39.     ......  
  40. }  

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public static void setSystemProcess() { try { ActivityManagerService m = mSelf; ServiceManager.addService("activity", m); ServiceManager.addService("meminfo", new MemBinder(m)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(m)); } ServiceManager.addService("permission", new PermissionController(m)); ApplicationInfo info = mSelf.mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info); synchronized (mSelf) { ProcessRecord app = mSelf.newProcessRecordLocked( mSystemThread.getApplicationThread(), info, info.processName); app.persistent = true; app.pid = MY_PID; app.maxAdj = SYSTEM_ADJ; mSelf.mProcessNames.put(app.processName, app.info.uid, app); synchronized (mSelf.mPidsSelfLocked) { mSelf.mPidsSelfLocked.put(app.pid, app); } mSelf.updateLruProcessLocked(app, true, true); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( "Unable to find android system package", e); } } ...... }        这个函数首先是将这个ActivityManagerService实例添加到ServiceManager中去托管,这样其它地方就可以通过ServiceManager.getService接口来访问这个全局唯一的ActivityManagerService实例了,接着又通过调用mSystemThread.installSystemApplicationInfo函数来把应用程序框架层下面的android包加载进来 ,这里的mSystemThread是一个ActivityThread类型的实例变量,它是在上面的Step 7中创建的,后面就是一些其它的初始化工作了。

        Step 10.  ActivityManagerService.systemReady

        这个函数是在上面的Step 6中的ServerThread.run函数在将系统中的一系列服务都初始化完毕之后才调用的,它定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:

view plain copy to clipboard print ?
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     public void systemReady(final Runnable goingCallback) {  
  6.         ......  
  7.   
  8.         synchronized (this) {  
  9.             ......  
  10.   
  11.             mMainStack.resumeTopActivityLocked(null);  
  12.         }  
  13.     }  
  14.   
  15.     ......  
  16. }  

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public void systemReady(final Runnable goingCallback) { ...... synchronized (this) { ...... mMainStack.resumeTopActivityLocked(null); } } ...... }        这个函数的内容比较多,这里省去无关的部分,主要关心启动Home应用程序的逻辑,这里就是通过mMainStack.resumeTopActivityLocked函数来启动Home应用程序的了,这里的mMainStack是一个ActivityStack类型的实例变量。

        Step 11. ActivityStack.resumeTopActivityLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

view plain copy to clipboard print ?
  1. public class ActivityStack {  
  2.     ......  
  3.   
  4.     final boolean resumeTopActivityLocked(ActivityRecord prev) {  
  5.         // Find the first activity that is not finishing.   
  6.         ActivityRecord next = topRunningActivityLocked(null);  
  7.   
  8.         ......  
  9.   
  10.         if (next == null) {  
  11.             // There are no more activities!  Let's just start up the   
  12.             // Launcher...   
  13.             if (mMainStack) {  
  14.                 return mService.startHomeActivityLocked();  
  15.             }  
  16.         }  
  17.   
  18.         ......  
  19.     }  
  20.   
  21.     ......  
  22. }  

public class ActivityStack { ...... final boolean resumeTopActivityLocked(ActivityRecord prev) { // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); ...... if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { return mService.startHomeActivityLocked(); } } ...... } ...... }        这里调用函数topRunningActivityLocked返回的是当前系统Activity堆栈最顶端的Activity,由于此时还没有Activity被启动过,因此,返回值为null,即next变量的值为null,于是就调用mService.startHomeActivityLocked语句,这里的mService就是前面在Step 7中创建的ActivityManagerService实例了。

        Step 12. ActivityManagerService.startHomeActivityLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:

view plain copy to clipboard print ?
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     boolean startHomeActivityLocked() {  
  6.         ......  
  7.   
  8.         Intent intent = new Intent(  
  9.             mTopAction,  
  10.             mTopData != null ? Uri.parse(mTopData) : null);  
  11.         intent.setComponent(mTopComponent);  
  12.         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {  
  13.             intent.addCategory(Intent.CATEGORY_HOME);  
  14.         }  
  15.         ActivityInfo aInfo =  
  16.             intent.resolveActivityInfo(mContext.getPackageManager(),  
  17.             STOCK_PM_FLAGS);  
  18.         if (aInfo != null) {  
  19.             intent.setComponent(new ComponentName(  
  20.                 aInfo.applicationInfo.packageName, aInfo.name));  
  21.             // Don't do this if the home app is currently being   
  22.             // instrumented.   
  23.             ProcessRecord app = getProcessRecordLocked(aInfo.processName,  
  24.                 aInfo.applicationInfo.uid);  
  25.             if (app == null || app.instrumentationClass == null) {  
  26.                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);  
  27.                 mMainStack.startActivityLocked(null, intent, nullnull0, aInfo,  
  28.                     nullnull000falsefalse);  
  29.             }  
  30.         }  
  31.   
  32.         return true;  
  33.     }  
  34.   
  35.     ......  
  36. }  

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... boolean startHomeActivityLocked() { ...... Intent intent = new Intent( mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); } ActivityInfo aInfo = intent.resolveActivityInfo(mContext.getPackageManager(), STOCK_PM_FLAGS); if (aInfo != null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being // instrumented. ProcessRecord app = getProcessRecordLocked(aInfo.processName, aInfo.applicationInfo.uid); if (app == null || app.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo, null, null, 0, 0, 0, false, false); } } return true; } ...... }        函数首先创建一个CATEGORY_HOME类型的Intent,然后通过Intent.resolveActivityInfo函数向PackageManagerService查询Category类型为HOME的Activity,这里我们假设只有系统自带的Launcher应用程序注册了HOME类型的Activity(见packages/apps/Launcher2/AndroidManifest.xml文件):

view plain copy to clipboard print ?
  1. <manifest  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.android.launcher"  
  4.     android:sharedUserId="@string/sharedUserId"  
  5.     >  
  6.   
  7.     ......  
  8.   
  9.     <application  
  10.         android:name="com.android.launcher2.LauncherApplication"  
  11.         android:process="@string/process"  
  12.         android:label="@string/application_name"  
  13.         android:icon="@drawable/ic_launcher_home">  
  14.   
  15.         <activity  
  16.             android:name="com.android.launcher2.Launcher"  
  17.             android:launchMode="singleTask"  
  18.             android:clearTaskOnLaunch="true"  
  19.             android:stateNotNeeded="true"  
  20.             android:theme="@style/Theme"  
  21.             android:screenOrientation="nosensor"  
  22.             android:windowSoftInputMode="stateUnspecified|adjustPan">  
  23.             <intent-filter>  
  24.                 <action android:name="android.intent.action.MAIN" />  
  25.                 <category android:name="android.intent.category.HOME" />  
  26.                 <category android:name="android.intent.category.DEFAULT" />  
  27.                 <category android:name="android.intent.category.MONKEY"/>  
  28.                 intent-filter>  
  29.         activity>  
  30.   
  31.         ......  
  32.     application>  
  33. manifest>  

...... ......

        因此,这里就返回com.android.launcher2.Launcher这个Activity了。由于是第一次启动这个Activity,接下来调用函数getProcessRecordLocked返回来的ProcessRecord值为null,于是,就调用mMainStack.startActivityLocked函数启动com.android.launcher2.Launcher这个Activity了,这里的mMainStack是一个ActivityStack类型的成员变量。

        Step 13.  ActivityStack.startActivityLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中       

 

       Step 14. Launcher.onCreate

        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/Launcher.java文件中:

view plain copy to clipboard print ?
  1. public final class Launcher extends Activity  
  2.         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {  
  3.     ......  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         ......  
  8.   
  9.         if (!mRestoring) {  
  10.             mModel.startLoader(thistrue);  
  11.         }  
  12.   
  13.         ......  
  14.     }  
  15.   
  16.     ......  
  17. }  

public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... @Override protected void onCreate(Bundle savedInstanceState) { ...... if (!mRestoring) { mModel.startLoader(this, true); } ...... } ...... }        这里的mModel是一个LauncherModel类型的成员变量,这里通过调用它的startLoader成员函数来执行加应用程序的操作。

        Step 15. LauncherModel.startLoader

        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

view plain copy to clipboard print ?
  1. public class LauncherModel extends BroadcastReceiver {  
  2.     ......  
  3.   
  4.     public void startLoader(Context context, boolean isLaunching) {  
  5.         ......  
  6.   
  7.                 synchronized (mLock) {  
  8.                      ......  
  9.   
  10.                      // Don't bother to start the thread if we know it's not going to do anything   
  11.                      if (mCallbacks != null && mCallbacks.get() != null) {  
  12.                          // If there is already one running, tell it to stop.   
  13.                          LoaderTask oldTask = mLoaderTask;  
  14.                          if (oldTask != null) {  
  15.                              if (oldTask.isLaunching()) {  
  16.                                  // don't downgrade isLaunching if we're already running   
  17.                                  isLaunching = true;  
  18.                              }  
  19.                              oldTask.stopLocked();  
  20.                  }  
  21.                  mLoaderTask = new LoaderTask(context, isLaunching);  
  22.                  sWorker.post(mLoaderTask);  
  23.                 }  
  24.            }  
  25.     }  
  26.   
  27.     ......  
  28. }  

public class LauncherModel extends BroadcastReceiver { ...... public void startLoader(Context context, boolean isLaunching) { ...... synchronized (mLock) { ...... // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { // If there is already one running, tell it to stop. LoaderTask oldTask = mLoaderTask; if (oldTask != null) { if (oldTask.isLaunching()) { // don't downgrade isLaunching if we're already running isLaunching = true; } oldTask.stopLocked(); } mLoaderTask = new LoaderTask(context, isLaunching); sWorker.post(mLoaderTask); } } } ...... }        这里不是直接加载应用程序,而是把加载应用程序的操作作为一个消息来处理。这里的sWorker是一个Handler,通过它的post方式把一个消息放在消息队列中去,然后系统就会调用传进去的参数mLoaderTask的run函数来处理这个消息,这个mLoaderTask是LoaderTask类型的实例,于是,下面就会执行LoaderTask类的run函数了。

        Step 16. LoaderTask.run

        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

view plain copy to clipboard print ?
  1. public class LauncherModel extends BroadcastReceiver {  
  2.     ......  
  3.   
  4.     private class LoaderTask implements Runnable {  
  5.         ......  
  6.   
  7.         public void run() {  
  8.             ......  
  9.   
  10.             keep_running: {  
  11.                 ......  
  12.   
  13.                 // second step   
  14.                 if (loadWorkspaceFirst) {  
  15.                     ......  
  16.                     loadAndBindAllApps();  
  17.                 } else {  
  18.                     ......  
  19.                 }  
  20.   
  21.                 ......  
  22.             }  
  23.   
  24.             ......  
  25.         }  
  26.   
  27.         ......  
  28.     }  
  29.   
  30.     ......  
  31. }  

public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... public void run() { ...... keep_running: { ...... // second step if (loadWorkspaceFirst) { ...... loadAndBindAllApps(); } else { ...... } ...... } ...... } ...... } ...... }        这里调用loadAndBindAllApps成员函数来进一步操作。

        Step 17. LoaderTask.loadAndBindAllApps
        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

view plain copy to clipboard print ?
  1. public class LauncherModel extends BroadcastReceiver {  
  2.     ......  
  3.   
  4.     private class LoaderTask implements Runnable {  
  5.         ......  
  6.   
  7.         private void loadAndBindAllApps() {  
  8.             ......  
  9.   
  10.             if (!mAllAppsLoaded) {  
  11.                 loadAllAppsByBatch();  
  12.                 if (mStopped) {  
  13.                     return;  
  14.                 }  
  15.                 mAllAppsLoaded = true;  
  16.             } else {  
  17.                 onlyBindAllApps();  
  18.             }  
  19.         }  
  20.   
  21.   
  22.         ......  
  23.     }  
  24.   
  25.     ......  
  26. }  

public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... private void loadAndBindAllApps() { ...... if (!mAllAppsLoaded) { loadAllAppsByBatch(); if (mStopped) { return; } mAllAppsLoaded = true; } else { onlyBindAllApps(); } } ...... } ...... }        由于还没有加载过应用程序,这里的mAllAppsLoaded为false,于是就继续调用loadAllAppsByBatch函数来进一步操作了。

        Step 18. LoaderTask.loadAllAppsByBatch
        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

view plain copy to clipboard print ?
  1. public class LauncherModel extends BroadcastReceiver {  
  2.     ......  
  3.   
  4.     private class LoaderTask implements Runnable {  
  5.         ......  
  6.   
  7.         private void loadAllAppsByBatch() {   
  8.             ......  
  9.   
  10.             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  11.             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  12.   
  13.             final PackageManager packageManager = mContext.getPackageManager();  
  14.             List apps = null;  
  15.   
  16.             int N = Integer.MAX_VALUE;  
  17.   
  18.             int startIndex;  
  19.             int i=0;  
  20.             int batchSize = -1;  
  21.             while (i < N && !mStopped) {  
  22.                 if (i == 0) {  
  23.                     mAllAppsList.clear();  
  24.                     ......  
  25.                     apps = packageManager.queryIntentActivities(mainIntent, 0);  
  26.                       
  27.                     ......  
  28.   
  29.                     N = apps.size();  
  30.                       
  31.                     ......  
  32.   
  33.                     if (mBatchSize == 0) {  
  34.                         batchSize = N;  
  35.                     } else {  
  36.                         batchSize = mBatchSize;  
  37.                     }  
  38.   
  39.                     ......  
  40.   
  41.                     Collections.sort(apps,  
  42.                         new ResolveInfo.DisplayNameComparator(packageManager));  
  43.                 }  
  44.   
  45.                 startIndex = i;  
  46.                 for (int j=0; i
  47.                     // This builds the icon bitmaps.   
  48.                     mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));  
  49.                     i++;  
  50.                 }  
  51.   
  52.                 final boolean first = i <= batchSize;  
  53.                 final Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  54.                 final ArrayList added = mAllAppsList.added;  
  55.                 mAllAppsList.added = new ArrayList();  
  56.               
  57.                 mHandler.post(new Runnable() {  
  58.                     public void run() {  
  59.                         final long t = SystemClock.uptimeMillis();  
  60.                         if (callbacks != null) {  
  61.                             if (first) {  
  62.                                 callbacks.bindAllApplications(added);  
  63.                             } else {  
  64.                                 callbacks.bindAppsAdded(added);  
  65.                             }  
  66.                             ......  
  67.                         } else {  
  68.                             ......  
  69.                         }  
  70.                     }  
  71.                 });  
  72.   
  73.                 ......  
  74.             }  
  75.   
  76.             ......  
  77.         }  
  78.   
  79.         ......  
  80.     }  
  81.   
  82.     ......  
  83. }  

public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... private void loadAllAppsByBatch() { ...... final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); final PackageManager packageManager = mContext.getPackageManager(); List apps = null; int N = Integer.MAX_VALUE; int startIndex; int i=0; int batchSize = -1; while (i < N && !mStopped) { if (i == 0) { mAllAppsList.clear(); ...... apps = packageManager.queryIntentActivities(mainIntent, 0); ...... N = apps.size(); ...... if (mBatchSize == 0) { batchSize = N; } else { batchSize = mBatchSize; } ...... Collections.sort(apps, new ResolveInfo.DisplayNameComparator(packageManager)); } startIndex = i; for (int j=0; i

view plain copy to clipboard print ?
  1. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  2. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  

final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);        接着从mContext变量中获得PackageManagerService的接口:

view plain copy to clipboard print ?
  1. final PackageManager packageManager = mContext.getPackageManager();  

final PackageManager packageManager = mContext.getPackageManager();

       下一步就是通过这个PackageManagerService.queryIntentActivities接口来取回所有Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity了。

       我们先进入到PackageManagerService.queryIntentActivities函数中看看是如何获得这些Activity的,然后再回到这个函数中来看其余操作。

       Step 19. PackageManagerService.queryIntentActivities

       这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

view plain copy to clipboard print ?
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public List queryIntentActivities(Intent intent,  
  5.             String resolvedType, int flags) {  
  6.         ......  
  7.   
  8.         synchronized (mPackages) {  
  9.             String pkgName = intent.getPackage();  
  10.             if (pkgName == null) {  
  11.                 return (List)mActivities.queryIntent(intent,  
  12.                         resolvedType, flags);  
  13.             }  
  14.   
  15.             ......  
  16.         }  
  17.   
  18.         ......  
  19.     }  
  20.   
  21.     ......  
  22. }  

class PackageManagerService extends IPackageManager.Stub { ...... public List queryIntentActivities(Intent intent, String resolvedType, int flags) { ...... synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { return (List)mActivities.queryIntent(intent, resolvedType, flags); } ...... } ...... } ...... }

       系统在启动PackageManagerService时,会把系统中的应用程序都解析一遍,然后把解析得到的Activity都保存在mActivities变量中,这里通过这个mActivities变量的queryIntent函数返回符合条件intent的Activity,这里要返回的便是Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity了。

        回到Step 18中的 LoaderTask.loadAllAppsByBatch函数中,从queryIntentActivities函数调用处返回所要求的Activity后,便调用函数tryGetCallbacks(oldCallbacks)得到一个返CallBack接口,这个接口是由Launcher类实现的,接着调用这个接口的.bindAllApplications函数来进一步操作。注意,这里又是通过消息来处理加载应用程序的操作的。

        Step 20. Launcher.bindAllApplications

        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/Launcher.java文件中:

view plain copy to clipboard print ?
  1. public final class Launcher extends Activity  
  2.         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {  
  3.     ......  
  4.   
  5.     private AllAppsView mAllAppsGrid;  
  6.   
  7.     ......  
  8.   
  9.     public void bindAllApplications(ArrayList apps) {  
  10.         mAllAppsGrid.setApps(apps);  
  11.     }  
  12.   
  13.     ......  
  14. }  

public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... private AllAppsView mAllAppsGrid; ...... public void bindAllApplications(ArrayList apps) { mAllAppsGrid.setApps(apps); } ...... }        这里的mAllAppsGrid是一个AllAppsView类型的变量,它的实际类型一般就是AllApps2D了。

        Step 21. AllApps2D.setApps

        这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/AllApps2D.java文件中:

view plain copy to clipboard print ?
  1. public class AllApps2D  
  2.     extends RelativeLayout  
  3.     implements AllAppsView,  
  4.         AdapterView.OnItemClickListener,  
  5.         AdapterView.OnItemLongClickListener,  
  6.         View.OnKeyListener,  
  7.         DragSource {  
  8.   
  9.     ......  
  10.   
  11.     public void setApps(ArrayList list) {  
  12.         mAllAppsList.clear();  
  13.         addApps(list);  
  14.     }  
  15.   
  16.     public void addApps(ArrayList list) {  
  17.         final int N = list.size();  
  18.   
  19.         for (int i=0; i
  20.             final ApplicationInfo item = list.get(i);  
  21.             int index = Collections.binarySearch(mAllAppsList, item,  
  22.                 LauncherModel.APP_NAME_COMPARATOR);  
  23.             if (index < 0) {  
  24.                 index = -(index+1);  
  25.             }  
  26.             mAllAppsList.add(index, item);  
  27.         }  
  28.         mAppsAdapter.notifyDataSetChanged();  
  29.     }  
  30.   
  31.     ......  
  32. }  

public class AllApps2D extends RelativeLayout implements AllAppsView, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnKeyListener, DragSource { ...... public void setApps(ArrayList list) { mAllAppsList.clear(); addApps(list); } public void addApps(ArrayList list) { final int N = list.size(); for (int i=0; i

        到了这里,系统默认的Home应用程序Launcher就把PackageManagerService中的应用程序加载进来了,当我们在屏幕上点击下面这个图标时,就会把刚才加载好的应用程序以图标的形式展示出来了:

        点击这个按钮时,便会响应Launcher.onClick函数:

view plain copy to clipboard print ?
  1. public final class Launcher extends Activity  
  2.         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {  
  3.     ......  
  4.   
  5.     public void onClick(View v) {  
  6.         Object tag = v.getTag();  
  7.         if (tag instanceof ShortcutInfo) {  
  8.             ......  
  9.         } else if (tag instanceof FolderInfo) {  
  10.             ......  
  11.         } else if (v == mHandleView) {  
  12.             if (isAllAppsVisible()) {  
  13.                 ......  
  14.             } else {  
  15.                 showAllApps(true);  
  16.             }  
  17.         }  
  18.     }  
  19.   
  20.     ......  
  21. }  

public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... public void onClick(View v) { Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { ...... } else if (tag instanceof FolderInfo) { ...... } else if (v == mHandleView) { if (isAllAppsVisible()) { ...... } else { showAllApps(true); } } } ...... }        接着就会调用showAllApps函数显示应用程序图标:

view plain copy to clipboard print ?
  1. public final class Launcher extends Activity  
  2.         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {  
  3.     ......  
  4.   
  5.     void showAllApps(boolean animated) {  
  6.         mAllAppsGrid.zoom(1.0f, animated);  
  7.   
  8.         ((View) mAllAppsGrid).setFocusable(true);  
  9.         ((View) mAllAppsGrid).requestFocus();  
  10.   
  11.         // TODO: fade these two too   
  12.         mDeleteZone.setVisibility(View.GONE);  
  13.     }  
  14.   
  15.     ......  
  16. }  

public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... void showAllApps(boolean animated) { mAllAppsGrid.zoom(1.0f, animated); ((View) mAllAppsGrid).setFocusable(true); ((View) mAllAppsGrid).requestFocus(); // TODO: fade these two too mDeleteZone.setVisibility(View.GONE); } ...... }        这样我们就可以看到系统中的应用程序了:



        当点击上面的这些应用程序图标时,便会响应AllApps2D.onItemClick函数:

view plain copy to clipboard print ?
  1. public class AllApps2D  
  2.     extends RelativeLayout  
  3.     implements AllAppsView,  
  4.         AdapterView.OnItemClickListener,  
  5.         AdapterView.OnItemLongClickListener,  
  6.         View.OnKeyListener,  
  7.         DragSource {  
  8.   
  9.     ......  
  10.   
  11.     public void onItemClick(AdapterView parent, View v, int position, long id) {  
  12.         ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);  
  13.         mLauncher.startActivitySafely(app.intent, app);  
  14.     }  
  15.   
  16.   
  17.     ......  
  18. }  

public class AllApps2D extends RelativeLayout implements AllAppsView, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnKeyListener, DragSource { ...... public void onItemClick(AdapterView parent, View v, int position, long id) { ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); mLauncher.startActivitySafely(app.intent, app); } ...... }         这里的成员变量mLauncher的类型为Launcher,于是就调用Launcher.startActivitySafely函数来启动应用程序了。

 

 

 

 七         Launcher    widget添加过程

 

           

 

Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。View在另外一个进程里显示,但事件的处理方法还是在原来的进程里。这有点像 X Window中的嵌入式窗口。 

 首先我们需要了解RemoteViews, AppWidgetHost, AppWidgetHostView等概念

RemoteViews:并不是一个真正的View,它没有实现View的接口,而只是一个用于描述View的实体。比如:创建View需要的资源ID和各个控件的事件响应方法。RemoteViews会通过进程间通信机制传递给AppWidgetHost。

AppWidgetHost

AppWidgetHost是真正容纳AppWidget的地方,它的主要功能有两个:

o 监听来自AppWidgetService的事件:

class Callbacks extends IAppWidgetHost.Stub { public void updateAppWidget(int appWidgetId,RemoteViews views) { Message msg = mHandler.obtainMessage(HANDLE_UPDATE); msg.arg1 = appWidgetId;msg.obj = views; msg.sendToTarget(); }   public void providerChanged(int appWidgetId,AppWidgetProviderInfo info) { Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);msg.arg1 = appWidgetId; msg.obj = info; msg.sendToTarget(); } }

这是主要处理update和provider_changed两个事件,根据这两个事件更新widget。

class UpdateHandler extends Handler { public UpdateHandler(Looper looper) { super(looper); }   public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_UPDATE: {updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); break; } case HANDLE_PROVIDER_CHANGED: {onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj); break; } } } }

o 另外一个功能就是创建AppWidgetHostView。前面我们说过RemoteViews不是真正的View,只是View的描述,而AppWidgetHostView才是真正的View。这里先创建AppWidgetHostView,然后通过AppWidgetService查询appWidgetId对应的RemoteViews,最后把RemoteViews传递给AppWidgetHostView去updateAppWidget。

public final AppWidgetHostView createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);view.setAppWidget(appWidgetId, appWidget); synchronized (mViews) { mViews.put(appWidgetId, view); }RemoteViews views = null; try { views = sService.getAppWidgetViews(appWidgetId); } catch(RemoteException e) { throw new RuntimeException("system server dead?", e); }view.updateAppWidget(views); return view; }

AppWidgetHostView

AppWidgetHostView是真正的View,但它只是一个容器,用来容纳实际的AppWidget的View。这个AppWidget的View是根据RemoteViews的描述来创建。这是在updateAppWidget里做的:

public void updateAppWidget(RemoteViews remoteViews) { ... if (content == null && layoutId ==mLayoutId) { try { remoteViews.reapply(mContext, mView); content = mView; recycled = true; if(LOGD) Log.d(TAG, "was able to recycled existing layout"); } catch (RuntimeException e) { exception= e; } }   // Try normal RemoteView inflation if (content == null) { try { content =remoteViews.apply(mContext, this); if (LOGD) Log.d(TAG, "had to inflate new layout"); } catch(RuntimeException e) { exception = e; } } ... if (!recycled) { prepareView(content);addView(content); }   if (mView != content) { removeView(mView); mView = content; } ... }

remoteViews.apply创建了实际的View,下面代码可以看出:

public View apply(Context context, ViewGroup parent) { View result = null;   Context c =prepareContext(context);   Resources r = c.getResources(); LayoutInflater inflater =(LayoutInflater) c .getSystemService(Context.LAYOUT_INFLATER_SERVICE);   inflater =inflater.cloneInContext(c); inflater.setFilter(this);   result = inflater.inflate(mLayoutId,parent, false);   performApply(result);   return result; }

Host的实现者

AppWidgetHost和AppWidgetHostView是在框架中定义的两个基类。应用程序可以利用这两个类来实现自己的Host。Launcher是缺省的桌面,它是一个Host的实现者。

LauncherAppWidgetHostView扩展了AppWidgetHostView,实现了对长按事件的处理。

LauncherAppWidgetHost扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例。

AppWidgetService

AppWidgetService存在的目的主要是解开AppWidgetProvider和AppWidgetHost之间的耦合。如果AppWidgetProvider和AppWidgetHost的关系固定死了,AppWidget就无法在任意进程里显示了。而有了AppWidgetService,AppWidgetProvider根本不需要知道自己的AppWidget在哪里显示了。

 

LauncherAppWidgetHostView: 扩展了AppWidgetHostView,实现了对长按事件的处理

LauncherAppWidgetHost: 扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例

24  /** 25   * Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView} 26   * which correctly captures all long-press events. This ensures that users can 27   * always pick up and move widgets. 28   */ 29  public class LauncherAppWidgetHost extends AppWidgetHost { 30      public LauncherAppWidgetHost(Context context, int hostId) { 31          super(context, hostId); 32      } 33       34      @Override 35      protected AppWidgetHostView onCreateView(Context context, int appWidgetId, 36              AppWidgetProviderInfo appWidget) { 37          return new LauncherAppWidgetHostView(context); 38      } 39  }

 

首先在Launcher.java中定义了如下两个变量

174      private AppWidgetManager mAppWidgetManager; 175      private LauncherAppWidgetHost mAppWidgetHost;

在onCreate函数中初始化,

224          mAppWidgetManager = AppWidgetManager.getInstance(this); 225          mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); 226          mAppWidgetHost.startListening(); 上述代码,获取mAppWidgetManager的实例,并创建LauncherAppWidgetHost,以及监听   AppWidgetManager只是应用程序与底层Service之间的一个桥梁,是Android中标准的aidl实现方式 应用程序通过AppWidgetManager调用Service中的方法 frameworks/base /  core  /  java  /  android  /  appwidget  /  AppWidgetManager.java 35  /** 36   * Updates AppWidget state; gets information about installed AppWidget providers and other 37   * AppWidget related state. 38   */ 39  public class AppWidgetManager { 197    static WeakHashMap sManagerCache = new WeakHashMap(); 198      static IAppWidgetService sService;   204      /** 205       * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context 206       * Context} object. 207       */ 208      public static AppWidgetManager getInstance(Context context) { 209          synchronized (sManagerCache) { 210              if (sService == null) { 211                  IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE); 212                  sService = IAppWidgetService.Stub.asInterface(b); 213              } 214 215              WeakReference ref = sManagerCache.get(context); 216              AppWidgetManager result = null; 217              if (ref != null) { 218                  result = ref.get(); 219              } 220              if (result == null) { 221                  result = new AppWidgetManager(context); 222                  sManagerCache.put(context, new WeakReference(result)); 223              } 224              return result; 225          } 226      } 227 228      private AppWidgetManager(Context context) { 229          mContext = context; 230          mDisplayMetrics = context.getResources().getDisplayMetrics(); 231      }

以上代码是设计模式中标准的单例模式

 

frameworks/base/ core / java / android / appwidget / AppWidgetHost.java

90      public AppWidgetHost(Context context, int hostId) { 91          mContext = context; 92          mHostId = hostId; 93          mHandler = new UpdateHandler(context.getMainLooper()); 94          synchronized (sServiceLock) { 95              if (sService == null) { 96                  IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE); 97                  sService = IAppWidgetService.Stub.asInterface(b); 98              } 99          } 100      }

可以看到AppWidgetHost有自己的HostId,Handler,和sService

93         mHandler = new UpdateHandler(context.getMainLooper());

这是啥用法呢?

参数为Looper,即消息处理放到此Looper的MessageQueue中,有哪些消息呢?

40      static final int HANDLE_UPDATE = 1; 41      static final int HANDLE_PROVIDER_CHANGED = 2;   48 49      class Callbacks extends IAppWidgetHost.Stub { 50          public void updateAppWidget(int appWidgetId, RemoteViews views) { 51              Message msg = mHandler.obtainMessage(HANDLE_UPDATE); 52              msg.arg1 = appWidgetId; 53              msg.obj = views; 54              msg.sendToTarget(); 55          } 56 57          public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) { 58              Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED); 59              msg.arg1 = appWidgetId; 60              msg.obj = info; 61              msg.sendToTarget(); 62          } 63      } 64 65      class UpdateHandler extends Handler { 66          public UpdateHandler(Looper looper) { 67              super(looper); 68          } 69           70          public void handleMessage(Message msg) { 71              switch (msg.what) { 72                  case HANDLE_UPDATE: { 73                      updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); 74                      break; 75                  } 76                  case HANDLE_PROVIDER_CHANGED: { 77                      onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj); 78                      break; 79                  } 80              } 81          } 82      }

通过以上可以看到主要有两中类型的消息,HANDLE_UPDATE和HANDLE_PROVIDER_CHANGED

处理即通过自身定义的方法

231      /** 232       * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk. 233       */ 234      protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) { 235          AppWidgetHostView v; 236          synchronized (mViews) { 237              v = mViews.get(appWidgetId); 238          } 239          if (v != null) { 240              v.updateAppWidget(null, AppWidgetHostView.UPDATE_FLAGS_RESET); 241          } 242      } 243 244      void updateAppWidgetView(int appWidgetId, RemoteViews views) { 245          AppWidgetHostView v; 246          synchronized (mViews) { 247              v = mViews.get(appWidgetId); 248          } 249          if (v != null) { 250              v.updateAppWidget(views, 0); 251          } 252      }

 

那么此消息是何时由谁发送的呢?

从以上的代码中看到AppWidgetHost定义了内部类Callback,扩展了类IAppWidgetHost.Stub,类Callback中负责发送以上消息

Launcher中会调用本类中的如下方法,

102      /** 103       * Start receiving onAppWidgetChanged calls for your AppWidgets.  Call this when your activity 104       * becomes visible, i.e. from onStart() in your Activity. 105       */ 106      public void startListening() { 107          int[] updatedIds; 108          ArrayList updatedViews = new ArrayList(); 109           110          try { 111              if (mPackageName == null) { 112                  mPackageName = mContext.getPackageName(); 113              } 114              updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews); 115          } 116          catch (RemoteException e) { 117              throw new RuntimeException("system server dead?", e); 118          } 119 120          final int N = updatedIds.length; 121          for (int i=0; i 
            updateAppWidgetView(updatedIds[i], updatedViews.get(i)); 123          } 124      } 最终调用AppWidgetService中的方法startListening方法,并把mCallbacks传过去,由Service负责发送消息   Launcher中添加Widget 在Launcher中添加widget,有两种途径,通过Menu或者长按桌面的空白区域,都会弹出Dialog,让用户选择添加 如下代码是当用户选择 1999          /** 2000           * Handle the action clicked in the "Add to home" dialog. 2001           */ 2002          public void onClick(DialogInterface dialog, int which) { 2003              Resources res = getResources(); 2004              cleanup(); 2005 2006              switch (which) { 2007                  case AddAdapter.ITEM_SHORTCUT: { 2008                      // Insert extra item to handle picking application 2009                      pickShortcut(); 2010                      break; 2011                  } 2012 2013                  case AddAdapter.ITEM_APPWIDGET: { 2014                      int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); 2015 2016                      Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); 2017                      pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 2018                      // start the pick activity 2019                      startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); 2020                      break; 2021                  }

当用户在Dialog中选择AddAdapter.ITEM_APPWIDGET时,首先会通过AppWidgethost分配一个appWidgetId,并最终调到AppWidgetService中去

同时发送Intent,其中保存有刚刚分配的appWidgetId,AppWidgetManager.EXTRA_APPWIDGET_ID

139      /** 140       * Get a appWidgetId for a host in the calling process. 141       * 142       * @return a appWidgetId 143       */ 144      public int allocateAppWidgetId() { 145          try { 146              if (mPackageName == null) { 147                  mPackageName = mContext.getPackageName(); 148              } 149              return sService.allocateAppWidgetId(mPackageName, mHostId); 150          } 151          catch (RemoteException e) { 152              throw new RuntimeException("system server dead?", e); 153          } 154      }   2016                      Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); 2017                      pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 2018                      // start the pick activity 2019                      startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); 这段代码之后,代码将会怎么执行呢,根据Log信息,可以看到代码将会执行到Setting应用中 packages/apps/Settings/   src  /   com  /   android  /   settings  /   AppWidgetPickActivity.java 此类将会通过AppWidgetService获取到当前系统已经安装的Widget,并显示出来 78      /** 79       * Create list entries for any custom widgets requested through 80       * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}. 81       */ 82      void putCustomAppWidgets(List items) { 83          final Bundle extras = getIntent().getExtras(); 84           85          // get and validate the extras they gave us 86          ArrayList customInfo = null; 87          ArrayList customExtras = null; 88          try_custom_items: { 89              customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO); 90              if (customInfo == null || customInfo.size() == 0) { 91                  Log.i(TAG, "EXTRA_CUSTOM_INFO not present."); 92                  break try_custom_items; 93              } 94 95              int customInfoSize = customInfo.size(); 96              for (int i=0; i 
                Parcelable p = customInfo.get(i); 98                  if (p == null || !(p instanceof AppWidgetProviderInfo)) { 99                      customInfo = null; 100                      Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i); 101                      break try_custom_items; 102                  } 103              } 104 105              customExtras = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_EXTRAS); 106              if (customExtras == null) { 107                  customInfo = null; 108                  Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS"); 109                  break try_custom_items; 110              } 111 112              int customExtrasSize = customExtras.size(); 113              if (customInfoSize != customExtrasSize) { 114                  Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize 115                          + " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize); 116                  break try_custom_items; 117              } 118 119 120              for (int i=0; i                 Parcelable p = customExtras.get(i); 122                  if (p == null || !(p instanceof Bundle)) { 123                      customInfo = null; 124                      customExtras = null; 125                      Log.e(TAG, "error using EXTRA_CUSTOM_EXTRAS index=" + i); 126                      break try_custom_items; 127                  } 128              } 129          } 130 131          if (LOGD) Log.d(TAG, "Using " + customInfo.size() + " custom items"); 132          putAppWidgetItems(customInfo, customExtras, items); 133      } 从上述代码中可以看到,可以放置用户自己定义的伪Widget 关于伪widget,个人有如下想法: 早期Android版本中的Google Search Bar就属于伪Widget,其实就是把widget做到Launcher中,但是用户体验与真widget并没有区别,个人猜想HTC的sense就是这样实现的。 优点:是不需要进程间的通信,效率将会更高,并且也可以规避点Widget开发的种种限制 缺点:导致Launcher代码庞大,不易于维护   用户选择完之后,代码如下 135      /** 136       * {@inheritDoc} 137       */ 138      @Override 139      public void onClick(DialogInterface dialog, int which) { 140          Intent intent = getIntentForPosition(which); 141           142          int result; 143          if (intent.getExtras() != null) { 144              // If there are any extras, it's because this entry is custom. 145              // Don't try to bind it, just pass it back to the app. 146              setResultData(RESULT_OK, intent); 147          } else { 148              try { 149                  mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent()); 150                  result = RESULT_OK; 151              } catch (IllegalArgumentException e) { 152                  // This is thrown if they're already bound, or otherwise somehow 153                  // bogus.  Set the result to canceled, and exit.  The app *should* 154                  // clean up at this point.  We could pass the error along, but 155                  // it's not clear that that's useful -- the widget will simply not 156                  // appear. 157                  result = RESULT_CANCELED; 158              } 159              setResultData(result, null); 160          } 161          finish(); 162      }   将会 149                  mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent()); 如果此次添加的Widget是intent.getComponent()的第一个实例,将会发送如下广播 171      /** 172       * Sent when an instance of an AppWidget is added to a host for the first time. 173       * This broadcast is sent at boot time if there is a AppWidgetHost installed with 174       * an instance for this provider. 175       *  176       * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context) 177       */ 178    public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED"; 紧接着会发送UPDATE广播 135      /** 136       * Sent when it is time to update your AppWidget. 137       * 138       * 

This may be sent in response to a new instance for this AppWidget provider having 139       * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval} 140       * having lapsed, or the system booting. 141       * 142       * 

143       * The intent will contain the following extras: 144       * 

145       *    146       *      147       *      150       *   151       * 
{@link #EXTRA_APPWIDGET_IDS}The appWidgetIds to update.  This may be all of the AppWidgets created for this 148       *     provider, or just a subset.  The system tries to send updates for as few AppWidget 149       *     instances as possible.
152       *  153     * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 154       */ 155    public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";

 待用户选择完要添加的widget之后,将会回到Launcher.java中的函数onActivityResult中

538                  case REQUEST_PICK_APPWIDGET: 539                      addAppWidget(data); 540                      break;

上述addAppWidget中做了哪些事情呢?

1174      void addAppWidget(Intent data) { 1175          // TODO: catch bad widget exception when sent 1176          int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 1177          AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId); 1178 1179          if (appWidget.configure != null) { 1180              // Launch over to configure widget, if needed 1181              Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); 1182              intent.setComponent(appWidget.configure); 1183              intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 1184 1185              startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET); 1186          } else { 1187              // Otherwise just add it 1188              onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data); 1189          } 1190      }

首先获取appWidgetId,再通过AppWidgetManager获取AppWidgetProviderInfo,最后判断此Widget是否存在ConfigActivity,如果存在则启动ConfigActivity,否则直接调用函数onActivityResult

541                  case REQUEST_CREATE_APPWIDGET: 542                      completeAddAppWidget(data, mAddItemCellInfo); 543                      break;

通过函数completeAddAppWidget把此widget的信息插入到数据库中,并添加到桌面上

873      /** 874       * Add a widget to the workspace. 875       * 876       * @param data The intent describing the appWidgetId. 877       * @param cellInfo The position on screen where to create the widget. 878       */ 879      private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) { 880          Bundle extras = data.getExtras(); 881          int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 882 883          if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString()); 884 885          AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); 886 887          // Calculate the grid spans needed to fit this widget 888          CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen); 889          int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight); 890 891          // Try finding open space on Launcher screen 892          final int[] xy = mCellCoordinates; 893          if (!findSlot(cellInfo, xy, spans[0], spans[1])) { 894              if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId); 895              return; 896          } 897 898          // Build Launcher-specific widget info and save to database 899          LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId); 900          launcherInfo.spanX = spans[0]; 901          launcherInfo.spanY = spans[1]; 902 903          LauncherModel.addItemToDatabase(this, launcherInfo, 904                  LauncherSettings.Favorites.CONTAINER_DESKTOP, 905                  mWorkspace.getCurrentScreen(), xy[0], xy[1], false); 906 907          if (!mRestoring) { 908              mDesktopItems.add(launcherInfo); 909 910              // Perform actual inflation because we're live 911              launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); 912 913              launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo); 914              launcherInfo.hostView.setTag(launcherInfo); 915 916              mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1], 917                      launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked()); 918          } 919      }

 

Launcher中删除widget

 长按一个widget,并拖入到DeleteZone中可实现删除

具体代码在DeleteZone中

92      public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, 93              DragView dragView, Object dragInfo) { 94          final ItemInfo item = (ItemInfo) dragInfo; 95 96          if (item.container == -1) return; 97 98          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { 99              if (item instanceof LauncherAppWidgetInfo) { 100                  mLauncher.removeAppWidget((LauncherAppWidgetInfo) item); 101              } 102          } else { 103              if (source instanceof UserFolder) { 104                  final UserFolder userFolder = (UserFolder) source; 105                  final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo(); 106                  // Item must be a ShortcutInfo otherwise it couldn't have been in the folder 107                  // in the first place. 108                  userFolderInfo.remove((ShortcutInfo)item); 109              } 110          } 111          if (item instanceof UserFolderInfo) { 112              final UserFolderInfo userFolderInfo = (UserFolderInfo)item; 113              LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo); 114              mLauncher.removeFolder(userFolderInfo); 115          } else if (item instanceof LauncherAppWidgetInfo) { 116              final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item; 117              final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost(); 118              if (appWidgetHost != null) { 119                  appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId); 120              } 121          } 122          LauncherModel.deleteItemFromDatabase(mLauncher, item); 123      }

删除时,判断删除的类型是否是AppWidget,如果是的话,要通过AppWidgetHost,删除AppWidetId,并最终从数据库中删除。

 

 

八     Launcher   celllayout介绍

 

           (1) 大家都知道workspace是有celllayout组成

Celllayout被划分为了4行4列的表格,用Boolean类型的mOccupied二维数组来标记每个cell是否被占用。在attrs.xml中定义了shortAxisCells和longAxisCells分别存储x轴和y轴方向的cell个数。在Celllayout构造函数中初始化。

(2) 内部类CellInfo为静态类,实现了ContextMenu.ContextMenuInfo接口,其对象用于存储cell的基本信息

VacantCell类用于存储空闲的cell,用到了同步机制用于管理对空闲位置的操作。所有的空cell都存储在vacantCells中。

cellX和cellY用于记录cell的位置,起始位0。如:(0,0) (0,1),每一页从新开始编号。

clearVacantCells作用是将Vacant清空:具体是释放每个cell,将list清空。

findVacantCellsFromOccupied从存放cell的数值中找到空闲的cell。在Launcher.Java中的restoreState方法中调用。

(3) mPortrait用于标记是横屏还是竖屏,FALSE表示竖屏,默认为FALSE。

(4)修改CellLayout页面上cell的布局:


CellLayout页面上默认的cell为4X4=16个,可以通过修改配置文件来达到修改目的。

在CellLayout.Java类的CellLayout(Context context, AttributeSet attrs, int defStyle)构造方法中用变量mShortAxisCells和mLongAxisCells存储行和列。

其值是在自定义配置文件attrs.xml中定义的,并在workspace_screen.xml中赋初值的,初值都为4,即4行、4列。可以在workspace_screen.xml修改对应的值。

注意:CellLayout构造方法中从attrs.xml中获取定义是这样的:mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);当workspace_screen.xml中没有给定义的变量赋值时,上面的4就起作用。

(5)Launcher(主屏/待机) App的BUG: 没有初始化定义CellLayout中屏幕方向的布尔值参数:

  1. Launcher App:\cupcake\packages\apps\Launcher

待机画面分为多层,桌面Desktop Items在\res\layout-*\workspace_screen.xml中置:

  1. ... ...
  2. launcher:shortAxisCells="4"
  3. launcher:longAxisCells="4"
  4. ... ...
  5. />

以上表示4行4列.

再看看com.android.launcher.CellLayout ,其中有定义屏幕方向的参数:

  1. private boolean mPortrait;

但是一直没有初始化,也就是mPortrait=false,桌面的单元格设置一直是以非竖屏(横屏)的设置定义进行初始化。

再来看看横屏和竖屏情况下的初始化不同之处,就可以看出BUG了:

  1. boolean[][] mOccupied;//二元单元格布尔值数组
  2.             if (mPortrait) {
  3.                 mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
  4. } else {
  5. mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
  6. }

如果我们满屏显示桌面(横向和纵向的单元格数不一致),而不是默认的只显示4行4列,则mShortAxisCells = 4, mLongAxisCells = 5,数组应该初始化是:new boolean[4][5],但是实际是按照非竖屏处理,初始化成了new boolean[5][4],会产生数组越界异常。

可以在构造函数中,添加通过屏幕方向初始化mPortrait,代码如下:

  1. public CellLayout(Context context, AttributeSet attrs, int defStyle)
  2. {
  3. super(context, attrs, defStyle);
  4. mPortrait = this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;// 新增代码
  5. ... ...

  好了就写这些,太累了,以后再补上其他跟Launcher有关的

   

 

       

更多相关文章

  1. android 调用 python
  2. Android自定义漂亮的Dialog
  3. 开源Mono框架将C#编程带到iPhone、Android和Wii
  4. 【Android(安卓)UI设计与开发】第06期:底部菜单栏(一)使用TabActivi
  5. String.xml
  6. Android(安卓)官方博客 - Android应用程序的内存分析
  7. Android中用seekbar控件控制歌曲的进度
  8. 保护你的隐私,五种控制Android应用的权限的方法
  9. Android(安卓)so lib库远程http下载和动态注册

随机推荐

  1. android UI设计的一些心得与问题解决(无效
  2. android jni ——Field & Method --> Acc
  3. android 中downloadmanager学习
  4. Android界面刷新
  5. 禁用Android系统Home键
  6. android 开发者选项
  7. 001——Binder 机制详解—Binder IPC 程
  8. [置顶] 我的Android进阶之旅------>Andro
  9. native.js获取手机硬件基本信息实例代码a
  10. 将ffmpeg移植到Android