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的代碼結構。

首先,是一些權限的聲明。例如:

  1. <uses-permission android:name="android.permission.CALL_PHONE" />  
  2. <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />  
  1. <uses-permission android:name="android.permission.CALL_PHONE" />  
  2. <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />  
  1. <uses-permission android:name="android.permission.CALL_PHONE" />  
  2. <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />  
 

這部分可以略過;

其次,Application的構成,如上圖:

 

(1)LauncherHomeScreenActivity

 
  1. <intent-filter>  
  2.  <action android:name="android.intent.action.MAIN" />  
  3.  <category android:name="android.intent.category.HOME"/>  
  4.  <category android:name="android.intent.category.DEFAULT" />  
  5. <category android:name="android.intent.category.MONKEY" /> </intent-filter>  
  1. <intent-filter>  
  2.  <action android:name="android.intent.action.MAIN" />  
  3.  <category android:name="android.intent.category.HOME"/>  
  4.  <category android:name="android.intent.category.DEFAULT" />  
  5. <category android:name="android.intent.category.MONKEY" /> </intent-filter>  
  1. <intent-filter>  
  2.  <action android:name="android.intent.action.MAIN" />  
  3.  <category android:name="android.intent.category.HOME"/>  
  4.  <category android:name="android.intent.category.DEFAULT" />  
  5. <category android:name="android.intent.category.MONKEY" /> </intent-filter>  

上面這段代碼就標誌着它是開機啓動後HomeActivity。通過Launcher.javaonCreat()的分析我們可以大致把握屏幕的主要活動:

 

  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.     }  
  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.     }  
  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.     }  
 

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

方法onSaveInstantceState()onRestoreInstanceState():爲了防止SensorLandPort佈局自動切換時數據被置空,通過onSaveInstanceState方法可以保存當前窗口的狀態,在即將佈局切換前將當前的Activity壓入歷史堆棧。如果我們的Activity在後臺沒有因爲運行內存吃緊被清理,則切換時回觸發onRestoreIntanceState()


(2)WallpaperChooser:設置牆紙。

同理我們從onCreat()作爲入口來分析這個活動的主要功能。

  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.     }  
  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.     }  
  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.     }  
 

 

(3)default_searchable

對於home中任意的Acitivty,使能系統缺省Search模式,這樣就可以使用android系統默認的search UI


 

(4)InstallShortcutReceiver

繼承自BroadcastReceiver,重寫onReceier()方法,對於發送來的Broadcast(這裏指Intent)進行過濾(IntentFilt)並且響應(這裏是InstallShortcut())。這裏分析下onReceive():

  1. <!-- Enable system-default search mode for any activity in Home -->  
  2. <!-- Intent received used to install shortcuts from other applications -->  
  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.     }  
  1. <!-- Enable system-default search mode for any activity in Home -->  
  2. <!-- Intent received used to install shortcuts from other applications -->  
  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.     }  
  1. <!-- Enable system-default search mode for any activity in Home -->  
  2. <!-- Intent received used to install shortcuts from other applications -->  
  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.     }  
 

其中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. ** Copyright 2008, The Android Open Source Project     
  6. **     
  7. ** Licensed under the Apache License, Version 2.0 (the "License");     
  8. ** you may not use this file except in compliance with the License.     
  9. ** You may obtain a copy of the License at     
  10. **     
  11. **     http://www.apache.org/licenses/LICENSE-2.0     
  12. **     
  13. ** Unless required by applicable law or agreed to in writing, software     
  14. ** distributed under the License is distributed on an "AS IS" BASIS,     
  15. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.     
  16. ** See the License for the specific language governing permissions and     
  17. ** limitations under the License.     
  18. */     
  19. -->     
  20. <manifest     
  21.     xmlns:android="http://schemas.android.com/apk/res/android"     
  22.     package="com.android.zkx_launcher"     
  23.     android:sharedUserId="@string/sharedUserId"     
  24.     >     
  25.      
  26.     <!-- 應用程序的包名 -->     
  27.     <!-- <original-package android:name="com.android.zkx_launcher2" /> -->     
  28.     <!-- 對系統資源的訪問權限 -->     
  29.     <permission     
  30.         android:name="com.android.zkx_launcher.permission.INSTALL_SHORTCUT"     
  31.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  32.         android:protectionLevel="normal"     
  33.         android:label="@string/permlab_install_shortcut"     
  34.         android:description="@string/permdesc_install_shortcut" />     
  35.     <permission     
  36.         android:name="com.android.zkx_launcher.permission.UNINSTALL_SHORTCUT"     
  37.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  38.         android:protectionLevel="normal"     
  39.         android:label="@string/permlab_uninstall_shortcut"     
  40.         android:description="@string/permdesc_uninstall_shortcut"/>     
  41.     <permission     
  42.         android:name="com.android.zkx_launcher.permission.READ_SETTINGS"     
  43.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  44.         android:protectionLevel="normal"     
  45.         android:label="@string/permlab_read_settings"     
  46.         android:description="@string/permdesc_read_settings"/>     
  47.     <permission     
  48.         android:name="com.android.zkx_launcher.permission.WRITE_SETTINGS"     
  49.         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"     
  50.         android:protectionLevel="normal"     
  51.         android:label="@string/permlab_write_settings"     
  52.         android:description="@string/permdesc_write_settings"/>     
  53.      
  54.     <uses-permission android:name="android.permission.CALL_PHONE" />     
  55.     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />     
  56.     <uses-permission android:name="android.permission.GET_TASKS" />     
  57.     <uses-permission android:name="android.permission.READ_CONTACTS"/>     
  58.     <uses-permission android:name="android.permission.SET_WALLPAPER" />     
  59.     <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />     
  60.     <uses-permission android:name="android.permission.VIBRATE" />     
  61.     <uses-permission android:name="android.permission.WRITE_SETTINGS" />     
  62.     <uses-permission android:name="android.permission.BIND_APPWIDGET" />     
  63.     <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />     
  64.     <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />     
  65.     <!-- 對應用程序的配置 -->     
  66.     <application     
  67.         android:name="LauncherApplication"     
  68.         android:process="@string/process"     
  69.         android:label="@string/application_name"     
  70.         android:icon="@drawable/ic_launcher_home">     
  71.         <!--配置應用程序額的名字,進程,標籤,和圖標             
  72.             label的值爲values/strings.xml中application_name 鍵值對的值     
  73.             icon爲drawable目錄下名爲的ic_launcher_home的圖片     
  74.              實際上該圖片的位置位於drawable-hdpi(高分辨率)目錄下,是個小房子這個主要是爲了支持多分辨率的.     
  75.             hdpi裏面主要放高分辨率的圖片,     
  76.              如WVGA (480x800),FWVGA (480x854)mdpi裏面主要放中等分辨率的圖片,     
  77.              如HVGA (320x480)ldpi裏面主要放低分辨率的圖片,     
  78.              如QVGA (240x320)系統會根據機器的分辨率來分別到這幾個文件夾裏面去找對應的圖片     
  79.              所以在開發程序時爲了兼容不同平臺不同屏幕,建議各自文件夾根據需求均存放不同版本圖片.     
  80.                   
  81.             只需要在res目錄下創建不同的layout文件夾,     
  82.             比如layout-640x360,layout-800x480,     
  83.             所有的layout文件在編譯之後都會寫入R.java裏,     
  84.             而系統會根據屏幕的大小自己選擇合適的layout進行使用 -->       
  85.                  
  86.         <!--設置intent-filter可以先啓動該Activity -->     
  87.         <activity     
  88.             android:name="Launcher"     
  89.             android:launchMode="singleTask"     
  90.             android:clearTaskOnLaunch="true"     
  91.             android:stateNotNeeded="true"     
  92.             android:theme="@style/Theme"     
  93.             android:screenOrientation="nosensor"     
  94.             android:windowSoftInputMode="stateUnspecified|adjustPan">     
  95.             <intent-filter>     
  96.                 <action android:name="android.intent.action.MAIN" />     
  97.                 <category android:name="android.intent.category.HOME" />     
  98.                 <category android:name="android.intent.category.DEFAULT" />     
  99.                 <category android:name="android.intent.category.MONKEY"/>     
  100.             </intent-filter>     
  101.         </activity>     
  102.              
  103.         <!--設置Wallpapaer的Activity -->     
  104.         <activity     
  105.             android:name="WallpaperChooser"     
  106.             android:label="@string/pick_wallpaper"     
  107.             android:icon="@drawable/ic_launcher_wallpaper"     
  108.             android:screenOrientation="nosensor"     
  109.             android:finishOnCloseSystemDialogs="true">     
  110.             <intent-filter>     
  111.                 <action android:name="android.intent.action.SET_WALLPAPER" />     
  112.                 <category android:name="android.intent.category.DEFAULT" />     
  113.             </intent-filter>     
  114.         </activity>     
  115.      
  116.         <!--安裝快捷方式的Intent -->     
  117.         <!-- Intent received used to install shortcuts from other applications -->     
  118.         <receiver     
  119.             android:name="InstallShortcutReceiver"     
  120.             android:permission="com.android.zkx_launcher.permission.INSTALL_SHORTCUT">     
  121.             <intent-filter>     
  122.                 <action android:name="com.android.zkx_launcher.action.INSTALL_SHORTCUT" />     
  123.             </intent-filter>     
  124.         </receiver>     
  125.      
  126.         <!--卸載快捷方式的Intent -->     
  127.         <!-- Intent received used to uninstall shortcuts from other applications -->     
  128.         <receiver     
  129.             android:name="UninstallShortcutReceiver"     
  130.             android:permission="com.android.zkx_launcher.permission.UNINSTALL_SHORTCUT">     
  131.             <intent-filter>     
  132.                 <action android:name="com.android.zkx_launcher.action.UNINSTALL_SHORTCUT" />     
  133.             </intent-filter>     
  134.         </receiver>     
  135.      
  136.         <!-- 供應商信息-->     
  137.         <!-- The settings provider contains Home's data, like the workspace favorites -->     
  138.         <provider     
  139.             android:name="LauncherProvider"     
  140.             android:authorities="com.android.zkx_launcher.settings"     
  141.             android:writePermission="com.android.zkx_launcher.permission.WRITE_SETTINGS"     
  142.             android:readPermission="com.android.zkx_launcher.permission.READ_SETTINGS" />     
  143.     </application>     
  144. </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資源。如果需要修改默認設置可以嘗試到這裏來找一找
<favorites xmlns:launcher="http://schemas.android.com/apk/res/com.unique.launcher">
    <!--  Far-left screen [0] -->

    <!--  Left screen [1] -->
    <appwidget
        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方向上所佔格數

        
    <!--  Middle screen [2] -->
    <search
        launcher:screen="2"
        launcher:x="0"
        launcher:y="0" />

 
    <appwidget
        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 " />


    <!--  Right screen [3] -->
    <appwidget
        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" />

 
    <appwidget
        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
    <!--  Far-right screen [4] -->

</favorites> 

 
 
四         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>


<!-- Enable system-default search mode for any activity in Home -->


<meta-data

        android:name="android.app.default_searchable"

        android:value="*"/>

安裝快捷方式的廣播接收器:


<!-- Intent received used to install shortcuts from other applications -->



<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>


<!-- Intent received used to uninstall shortcuts from other applications -->

卸載快捷方式的廣播接收器:


<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操作:


<!-- The settings provider contains Home's data, like the workspace favorites -->


<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.
<manifest標籤頭部還應聲明:

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文件中:
  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. }  
  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. }  
  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. }  
        SystemServer組件是由Zygote進程負責啓動的,啓動的時候就會調用它的main函數,這個函數主要調用了JNI方法init1來做一些系統初始化的工作。

        Step 2. SystemServer.init1

        這個函數是一個JNI方法,實現在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:

  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  
  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  
  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  
        這個函數很簡單,只是調用了system_init函數來進一步執行操作。

        Step 3. libsystem_server.system_init

        函數system_init實現在libsystem_server庫中,源代碼位於frameworks/base/cmds/system_server/library/system_init.cpp文件中:

  1. extern "C" status_t system_init()  
  2. {  
  3.     LOGI("Entered system_init()");  
  4.   
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.   
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp<GrimReaper> 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. }  
  1. extern "C" status_t system_init()  
  2. {  
  3.     LOGI("Entered system_init()");  
  4.   
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.   
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp<GrimReaper> 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. }  
  1. extern "C" status_t system_init()  
  2. {  
  3.     LOGI("Entered system_init()");  
  4.   
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.   
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp<GrimReaper> 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. }  
        這個函數首先會初始化SurfaceFlinger、SensorService、AudioFlinger、MediaPlayerService、CameraService和AudioPolicyService這幾個服務,然後就通過系統全局唯一的AndroidRuntime實例變量runtime的callStatic來調用SystemServer的init2函數了。關於這個AndroidRuntime實例變量runtime的相關資料,可能參考前面一篇文章Android應用程序進程啓動過程的源代碼分析一文。

        Step 4. AndroidRuntime.callStatic

        這個函數定義在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

  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. }  
  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. }  
  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. }  
        這個函數調用由參數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文件中:

  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. }  
  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. }  
  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. }  
        這個函數創建了一個ServerThread線程,PackageManagerService服務就是這個線程中啓動的了。這裏調用了ServerThread實例thr的start函數之後,下面就會執行這個實例的run函數了。

        Step 6. ServerThread.run

        這個函數定義在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

  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. }  
  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. }  
  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. }  
        這個函數除了啓動PackageManagerService服務之外,還啓動了其它很多的服務,例如在前面學習Activity和Service的幾篇文章中經常看到的ActivityManagerService服務,有興趣的讀者可以自己研究一下。
 
 Step 7. ActivityManagerService.main

        這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:

  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. }  
  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. }  
  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. }  
        這個函數首先通過AThread線程對象來內部創建了一個ActivityManagerService實例,然後將這個實例保存其成員變量mService中,接着又把這個ActivityManagerService實例保存在ActivityManagerService類的靜態成員變量mSelf中,最後初始化其它成員變量,就結束了。

        Step 8. PackageManagerService.main

這個函數定義在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:
  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. }  
  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. }  
  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. }  
        這個函數創建了一個PackageManagerService服務實例,然後把這個服務添加到ServiceManager中去,ServiceManager是Android系統Binder進程間通信機制的守護進程,負責管理系統中的Binder對象,在創建這個PackageManagerService服務實例時,會在PackageManagerService類的構造函數中開始執行安裝應用程序的過程:
  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. }  
  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. }  
  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. }  
        這裏會調用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文件中:

  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. }  
  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. }  
  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. }  
        這個函數首先是將這個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文件中:

  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. }  
  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. }  
  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. }  
        這個函數的內容比較多,這裏省去無關的部分,主要關心啓動Home應用程序的邏輯,這裏就是通過mMainStack.resumeTopActivityLocked函數來啓動Home應用程序的了,這裏的mMainStack是一個ActivityStack類型的實例變量。

        Step 11. ActivityStack.resumeTopActivityLocked

        這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

  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. }  
  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. }  
  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. }  
        這裏調用函數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文件中:

  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. }  
  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. }  
  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. }  
        函數首先創建一個CATEGORY_HOME類型的Intent,然後通過Intent.resolveActivityInfo函數向PackageManagerService查詢Category類型爲HOME的Activity,這裏我們假設只有系統自帶的Launcher應用程序註冊了HOME類型的Activity(見packages/apps/Launcher2/AndroidManifest.xml文件):

  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>  
  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>  
  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文件中:

  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. }  
  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. }  
  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. }  
        這裏的mModel是一個LauncherModel類型的成員變量,這裏通過調用它的startLoader成員函數來執行加應用程序的操作。

        Step 15. LauncherModel.startLoader

        這個函數定義在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

  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. }  
  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. }  
  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. }  
        這裏不是直接加載應用程序,而是把加載應用程序的操作作爲一個消息來處理。這裏的sWorker是一個Handler,通過它的post方式把一個消息放在消息隊列中去,然後系統就會調用傳進去的參數mLoaderTask的run函數來處理這個消息,這個mLoaderTask是LoaderTask類型的實例,於是,下面就會執行LoaderTask類的run函數了。

        Step 16. LoaderTask.run

        這個函數定義在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

  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. }  
  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. }  
  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. }  
        這裏調用loadAndBindAllApps成員函數來進一步操作。

        Step 17. LoaderTask.loadAndBindAllApps
        這個函數定義在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

  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. }  
  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. }  
  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. }  
        由於還沒有加載過應用程序,這裏的mAllAppsLoaded爲false,於是就繼續調用loadAllAppsByBatch函數來進一步操作了。

        Step 18. LoaderTask.loadAllAppsByBatch
        這個函數定義在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:

  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<ResolveInfo> 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<N && j<batchSize; j++) {  
  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<ApplicationInfo> added = mAllAppsList.added;  
  55.                 mAllAppsList.added = new ArrayList<ApplicationInfo>();  
  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. }  
  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<ResolveInfo> 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<N && j<batchSize; j++) {  
  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<ApplicationInfo> added = mAllAppsList.added;  
  55.                 mAllAppsList.added = new ArrayList<ApplicationInfo>();  
  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. }  
  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<ResolveInfo> 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<N && j<batchSize; j++) {  
  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<ApplicationInfo> added = mAllAppsList.added;  
  55.                 mAllAppsList.added = new ArrayList<ApplicationInfo>();  
  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. }  
        函數首先構造一個CATEGORY_LAUNCHER類型的Intent:

  1. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  2. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  1. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  2. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  1. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  2. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
        接着從mContext變量中獲得PackageManagerService的接口:

  1. final PackageManager packageManager = mContext.getPackageManager();  
  1. final PackageManager packageManager = mContext.getPackageManager();  
  1. 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文件中:

  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public List<ResolveInfo> 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<ResolveInfo>)mActivities.queryIntent(intent,  
  12.                         resolvedType, flags);  
  13.             }  
  14.   
  15.             ......  
  16.         }  
  17.   
  18.         ......  
  19.     }  
  20.   
  21.     ......  
  22. }  
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public List<ResolveInfo> 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<ResolveInfo>)mActivities.queryIntent(intent,  
  12.                         resolvedType, flags);  
  13.             }  
  14.   
  15.             ......  
  16.         }  
  17.   
  18.         ......  
  19.     }  
  20.   
  21.     ......  
  22. }  
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public List<ResolveInfo> 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<ResolveInfo>)mActivities.queryIntent(intent,  
  12.                         resolvedType, flags);  
  13.             }  
  14.   
  15.             ......  
  16.         }  
  17.   
  18.         ......  
  19.     }  
  20.   
  21.     ......  
  22. }  

       系統在啓動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文件中:

  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<ApplicationInfo> apps) {  
  10.         mAllAppsGrid.setApps(apps);  
  11.     }  
  12.   
  13.     ......  
  14. }  
  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<ApplicationInfo> apps) {  
  10.         mAllAppsGrid.setApps(apps);  
  11.     }  
  12.   
  13.     ......  
  14. }  
  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<ApplicationInfo> apps) {  
  10.         mAllAppsGrid.setApps(apps);  
  11.     }  
  12.   
  13.     ......  
  14. }  
        這裏的mAllAppsGrid是一個AllAppsView類型的變量,它的實際類型一般就是AllApps2D了。

        Step 21. AllApps2D.setApps

        這個函數定義在packages/apps/Launcher2/src/com/android/launcher2/AllApps2D.java文件中:

  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<ApplicationInfo> list) {  
  12.         mAllAppsList.clear();  
  13.         addApps(list);  
  14.     }  
  15.   
  16.     public void addApps(ArrayList<ApplicationInfo> list) {  
  17.         final int N = list.size();  
  18.   
  19.         for (int i=0; i<N; 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. }  
  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<ApplicationInfo> list) {  
  12.         mAllAppsList.clear();  
  13.         addApps(list);  
  14.     }  
  15.   
  16.     public void addApps(ArrayList<ApplicationInfo> list) {  
  17.         final int N = list.size();  
  18.   
  19.         for (int i=0; i<N; 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. }  
  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<ApplicationInfo> list) {  
  12.         mAllAppsList.clear();  
  13.         addApps(list);  
  14.     }  
  15.   
  16.     public void addApps(ArrayList<ApplicationInfo> list) {  
  17.         final int N = list.size();  
  18.   
  19.         for (int i=0; i<N; 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. }  
        函數setApps首先清空mAllAppsList列表,然後調用addApps函數來爲上一步得到的每一個應用程序創建一個ApplicationInfo實例了,有了這些ApplicationInfo實例之後,就可以在桌面上展示系統中所有的應用程序了。

        到了這裏,系統默認的Home應用程序Launcher就把PackageManagerService中的應用程序加載進來了,當我們在屏幕上點擊下面這個圖標時,就會把剛纔加載好的應用程序以圖標的形式展示出來了:

        點擊這個按鈕時,便會響應Launcher.onClick函數:

  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. }  
  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. }  
  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. }  
        接着就會調用showAllApps函數顯示應用程序圖標:

  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. }  
  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. }  
  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. }  
        這樣我們就可以看到系統中的應用程序了:



        當點擊上面的這些應用程序圖標時,便會響應AllApps2D.onItemClick函數:

  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. }  
  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. }  
  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. }  
        這裏的成員變量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的事件:

  1. class Callbacks extends IAppWidgetHost.<SPAN style="COLOR: #202020">Stub</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>public<SPAN> </SPAN><SPAN style="COLOR: #993333">void</SPAN><SPAN> </SPAN>updateAppWidget<SPAN>(</SPAN><SPAN style="COLOR: #993333">int</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN>RemoteViews views<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>Message msg<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>mHandler.<SPAN style="COLOR: #202020">obtainMessage</SPAN><SPAN>(</SPAN>HANDLE_UPDATE<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>msg.<SPAN style="COLOR: #202020">arg1</SPAN><SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">;</SPAN>msg.<SPAN style="COLOR: #202020">obj</SPAN><SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>views<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>msg.<SPAN style="COLOR: #202020">sendToTarget</SPAN><SPAN>(</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>  public<SPAN> </SPAN><SPAN style="COLOR: #993333">void</SPAN><SPAN> </SPAN>providerChanged<SPAN>(</SPAN><SPAN style="COLOR: #993333">int</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN>AppWidgetProviderInfo info<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>Message msg<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>mHandler.<SPAN style="COLOR: #202020">obtainMessage</SPAN><SPAN>(</SPAN>HANDLE_PROVIDER_CHANGED<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN>msg.<SPAN style="COLOR: #202020">arg1</SPAN><SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>msg.<SPAN style="COLOR: #202020">obj</SPAN><SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>info<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>msg.<SPAN style="COLOR: #202020">sendToTarget</SPAN><SPAN>(</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN>  
  1. class Callbacks extends IAppWidgetHost.<span style="color:#202020;">Stub</span><span> </span><span>{</span><span> </span>public<span> </span><span style="color:#993333;">void</span><span> </span>updateAppWidget<span>(</span><span style="color:#993333;">int</span><span> </span>appWidgetId<span style="color:#339933;">,</span>RemoteViews views<span>)</span><span> </span><span>{</span><span> </span>Message msg<span> </span><span style="color:#339933;">=</span><span> </span>mHandler.<span style="color:#202020;">obtainMessage</span><span>(</span>HANDLE_UPDATE<span>)</span><span style="color:#339933;">;</span><span> </span>msg.<span style="color:#202020;">arg1</span><span> </span><span style="color:#339933;">=</span><span> </span>appWidgetId<span style="color:#339933;">;</span>msg.<span style="color:#202020;">obj</span><span> </span><span style="color:#339933;">=</span><span> </span>views<span style="color:#339933;">;</span><span> </span>msg.<span style="color:#202020;">sendToTarget</span><span>(</span><span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>  public<span> </span><span style="color:#993333;">void</span><span> </span>providerChanged<span>(</span><span style="color:#993333;">int</span><span> </span>appWidgetId<span style="color:#339933;">,</span>AppWidgetProviderInfo info<span>)</span><span> </span><span>{</span><span> </span>Message msg<span> </span><span style="color:#339933;">=</span><span> </span>mHandler.<span style="color:#202020;">obtainMessage</span><span>(</span>HANDLE_PROVIDER_CHANGED<span>)</span><span style="color:#339933;">;</span>msg.<span style="color:#202020;">arg1</span><span> </span><span style="color:#339933;">=</span><span> </span>appWidgetId<span style="color:#339933;">;</span><span> </span>msg.<span style="color:#202020;">obj</span><span> </span><span style="color:#339933;">=</span><span> </span>info<span style="color:#339933;">;</span><span> </span>msg.<span style="color:#202020;">sendToTarget</span><span>(</span><span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span><span>}</span>  

這是主要處理update和provider_changed兩個事件,根據這兩個事件更新widget。

  1. class UpdateHandler extends Handler<SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>public UpdateHandler<SPAN>(</SPAN>Looper looper<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>super<SPAN>(</SPAN>looper<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>  public<SPAN> </SPAN><SPAN style="COLOR: #993333">void</SPAN><SPAN> </SPAN>handleMessage<SPAN>(</SPAN>Message msg<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN><SPAN>switch</SPAN><SPAN> </SPAN><SPAN>(</SPAN>msg.<SPAN style="COLOR: #202020">what</SPAN><SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN><SPAN>case</SPAN><SPAN> </SPAN>HANDLE_UPDATE<SPAN style="COLOR: #339933">:</SPAN><SPAN> </SPAN><SPAN>{</SPAN>updateAppWidgetView<SPAN>(</SPAN>msg.<SPAN style="COLOR: #202020">arg1</SPAN><SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN>(</SPAN>RemoteViews<SPAN>)</SPAN>msg.<SPAN style="COLOR: #202020">obj</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">break</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>case</SPAN><SPAN> </SPAN>HANDLE_PROVIDER_CHANGED<SPAN style="COLOR: #339933">:</SPAN><SPAN> </SPAN><SPAN>{</SPAN>onProviderChanged<SPAN>(</SPAN>msg.<SPAN style="COLOR: #202020">arg1</SPAN><SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN>(</SPAN>AppWidgetProviderInfo<SPAN>)</SPAN>msg.<SPAN style="COLOR: #202020">obj</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">break</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN>  
  1. class UpdateHandler extends Handler<span> </span><span>{</span><span> </span>public UpdateHandler<span>(</span>Looper looper<span>)</span><span> </span><span>{</span><span> </span>super<span>(</span>looper<span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>  public<span> </span><span style="color:#993333;">void</span><span> </span>handleMessage<span>(</span>Message msg<span>)</span><span> </span><span>{</span><span> </span><span>switch</span><span> </span><span>(</span>msg.<span style="color:#202020;">what</span><span>)</span><span> </span><span>{</span><span> </span><span>case</span><span> </span>HANDLE_UPDATE<span style="color:#339933;">:</span><span> </span><span>{</span>updateAppWidgetView<span>(</span>msg.<span style="color:#202020;">arg1</span><span style="color:#339933;">,</span><span> </span><span>(</span>RemoteViews<span>)</span>msg.<span style="color:#202020;">obj</span><span>)</span><span style="color:#339933;">;</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">break</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span><span>case</span><span> </span>HANDLE_PROVIDER_CHANGED<span style="color:#339933;">:</span><span> </span><span>{</span>onProviderChanged<span>(</span>msg.<span style="color:#202020;">arg1</span><span style="color:#339933;">,</span><span> </span><span>(</span>AppWidgetProviderInfo<span>)</span>msg.<span style="color:#202020;">obj</span><span>)</span><span style="color:#339933;">;</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">break</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span><span>}</span><span> </span><span>}</span><span> </span><span>}</span>  

o 另外一個功能就是創建AppWidgetHostView。前面我們說過RemoteViews不是真正的View,只是View的描述,而AppWidgetHostView纔是真正的View。這裏先創建AppWidgetHostView,然後通過AppWidgetService查詢appWidgetId對應的RemoteViews,最後把RemoteViews傳遞給AppWidgetHostView去updateAppWidget。

  1. public final AppWidgetHostView createView<SPAN>(</SPAN>Context context<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN style="COLOR: #993333">int</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>AppWidgetProviderInfo appWidget<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>AppWidgetHostView view<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>onCreateView<SPAN>(</SPAN>context<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>appWidget<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN>view.<SPAN style="COLOR: #202020">setAppWidget</SPAN><SPAN>(</SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>appWidget<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>synchronized<SPAN> </SPAN><SPAN>(</SPAN>mViews<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>mViews.<SPAN style="COLOR: #202020">put</SPAN><SPAN>(</SPAN>appWidgetId<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>view<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN>RemoteViews views<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">null</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>try<SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>views<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>sService.<SPAN style="COLOR: #202020">getAppWidgetViews</SPAN><SPAN>(</SPAN>appWidgetId<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>catch<SPAN>(</SPAN>RemoteException e<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>throw new RuntimeException<SPAN>(</SPAN><SPAN>"system server dead?"</SPAN><SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>e<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN>view.<SPAN style="COLOR: #202020">updateAppWidget</SPAN><SPAN>(</SPAN>views<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>return</SPAN><SPAN> </SPAN>view<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN>  
  1. public final AppWidgetHostView createView<span>(</span>Context context<span style="color:#339933;">,</span><span> </span><span style="color:#993333;">int</span><span> </span>appWidgetId<span style="color:#339933;">,</span><span> </span>AppWidgetProviderInfo appWidget<span>)</span><span> </span><span>{</span><span> </span>AppWidgetHostView view<span> </span><span style="color:#339933;">=</span><span> </span>onCreateView<span>(</span>context<span style="color:#339933;">,</span><span> </span>appWidgetId<span style="color:#339933;">,</span><span> </span>appWidget<span>)</span><span style="color:#339933;">;</span>view.<span style="color:#202020;">setAppWidget</span><span>(</span>appWidgetId<span style="color:#339933;">,</span><span> </span>appWidget<span>)</span><span style="color:#339933;">;</span><span> </span>synchronized<span> </span><span>(</span>mViews<span>)</span><span> </span><span>{</span><span> </span>mViews.<span style="color:#202020;">put</span><span>(</span>appWidgetId<span style="color:#339933;">,</span><span> </span>view<span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span>RemoteViews views<span> </span><span style="color:#339933;">=</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">null</span><span style="color:#339933;">;</span><span> </span>try<span> </span><span>{</span><span> </span>views<span> </span><span style="color:#339933;">=</span><span> </span>sService.<span style="color:#202020;">getAppWidgetViews</span><span>(</span>appWidgetId<span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>catch<span>(</span>RemoteException e<span>)</span><span> </span><span>{</span><span> </span>throw new RuntimeException<span>(</span><span>"system server dead?"</span><span style="color:#339933;">,</span><span> </span>e<span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span>view.<span style="color:#202020;">updateAppWidget</span><span>(</span>views<span>)</span><span style="color:#339933;">;</span><span> </span><span>return</span><span> </span>view<span style="color:#339933;">;</span><span> </span><span>}</span>  

AppWidgetHostView

AppWidgetHostView是真正的View,但它只是一個容器,用來容納實際的AppWidget的View。這個AppWidget的View是根據RemoteViews的描述來創建。這是在updateAppWidget裏做的:

  1. public<SPAN> </SPAN><SPAN style="COLOR: #993333">void</SPAN><SPAN> </SPAN>updateAppWidget<SPAN>(</SPAN>RemoteViews remoteViews<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>...<SPAN> </SPAN><SPAN>if</SPAN><SPAN> </SPAN><SPAN>(</SPAN>content<SPAN> </SPAN><SPAN style="COLOR: #339933">==</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">null</SPAN><SPAN> </SPAN><SPAN style="COLOR: #339933">&&</SPAN><SPAN> </SPAN>layoutId<SPAN> </SPAN><SPAN style="COLOR: #339933">==</SPAN>mLayoutId<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>try<SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>remoteViews.<SPAN style="COLOR: #202020">reapply</SPAN><SPAN>(</SPAN>mContext<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>mView<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>content<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>mView<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>recycled<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">true</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>if</SPAN><SPAN>(</SPAN>LOGD<SPAN>)</SPAN><SPAN> </SPAN>Log.<SPAN style="COLOR: #202020">d</SPAN><SPAN>(</SPAN>TAG<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN>"was able to recycled existing layout"</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>catch<SPAN> </SPAN><SPAN>(</SPAN>RuntimeException e<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>exception<SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>e<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN> <SPAN> </SPAN><SPAN style="FONT-STYLE: italic; COLOR: #666666">// Try normal RemoteView inflation</SPAN><SPAN> </SPAN><SPAN>if</SPAN><SPAN> </SPAN><SPAN>(</SPAN>content<SPAN> </SPAN><SPAN style="COLOR: #339933">==</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">null</SPAN><SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>try<SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>content<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN>remoteViews.<SPAN style="COLOR: #202020">apply</SPAN><SPAN>(</SPAN>mContext<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>this<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>if</SPAN><SPAN> </SPAN><SPAN>(</SPAN>LOGD<SPAN>)</SPAN><SPAN> </SPAN>Log.<SPAN style="COLOR: #202020">d</SPAN><SPAN>(</SPAN>TAG<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN>"had to inflate new layout"</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>catch<SPAN>(</SPAN>RuntimeException e<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>exception<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>e<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>...<SPAN> </SPAN><SPAN>if</SPAN><SPAN> </SPAN><SPAN>(</SPAN><SPAN style="COLOR: #339933">!</SPAN>recycled<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>prepareView<SPAN>(</SPAN>content<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN>addView<SPAN>(</SPAN>content<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN> <SPAN> </SPAN><SPAN>if</SPAN><SPAN> </SPAN><SPAN>(</SPAN>mView<SPAN> </SPAN><SPAN style="COLOR: #339933">!=</SPAN><SPAN> </SPAN>content<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>removeView<SPAN>(</SPAN>mView<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>mView<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>content<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN><SPAN> </SPAN>...<SPAN> </SPAN><SPAN>}</SPAN>  
  1. public<span> </span><span style="color:#993333;">void</span><span> </span>updateAppWidget<span>(</span>RemoteViews remoteViews<span>)</span><span> </span><span>{</span><span> </span>...<span> </span><span>if</span><span> </span><span>(</span>content<span> </span><span style="color:#339933;">==</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">null</span><span> </span><span style="color:#339933;">&&</span><span> </span>layoutId<span> </span><span style="color:#339933;">==</span>mLayoutId<span>)</span><span> </span><span>{</span><span> </span>try<span> </span><span>{</span><span> </span>remoteViews.<span style="color:#202020;">reapply</span><span>(</span>mContext<span style="color:#339933;">,</span><span> </span>mView<span>)</span><span style="color:#339933;">;</span><span> </span>content<span> </span><span style="color:#339933;">=</span><span> </span>mView<span style="color:#339933;">;</span><span> </span>recycled<span> </span><span style="color:#339933;">=</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">true</span><span style="color:#339933;">;</span><span> </span><span>if</span><span>(</span>LOGD<span>)</span><span> </span>Log.<span style="color:#202020;">d</span><span>(</span>TAG<span style="color:#339933;">,</span><span> </span><span>"was able to recycled existing layout"</span><span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>catch<span> </span><span>(</span>RuntimeException e<span>)</span><span> </span><span>{</span><span> </span>exception<span style="color:#339933;">=</span><span> </span>e<span style="color:#339933;">;</span><span> </span><span>}</span><span> </span><span>}</span><span> </span> <span> </span><span style="color:#666666;FONT-STYLE: italic">// Try normal RemoteView inflation</span><span> </span><span>if</span><span> </span><span>(</span>content<span> </span><span style="color:#339933;">==</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">null</span><span>)</span><span> </span><span>{</span><span> </span>try<span> </span><span>{</span><span> </span>content<span> </span><span style="color:#339933;">=</span>remoteViews.<span style="color:#202020;">apply</span><span>(</span>mContext<span style="color:#339933;">,</span><span> </span>this<span>)</span><span style="color:#339933;">;</span><span> </span><span>if</span><span> </span><span>(</span>LOGD<span>)</span><span> </span>Log.<span style="color:#202020;">d</span><span>(</span>TAG<span style="color:#339933;">,</span><span> </span><span>"had to inflate new layout"</span><span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>catch<span>(</span>RuntimeException e<span>)</span><span> </span><span>{</span><span> </span>exception<span> </span><span style="color:#339933;">=</span><span> </span>e<span style="color:#339933;">;</span><span> </span><span>}</span><span> </span><span>}</span><span> </span>...<span> </span><span>if</span><span> </span><span>(</span><span style="color:#339933;">!</span>recycled<span>)</span><span> </span><span>{</span><span> </span>prepareView<span>(</span>content<span>)</span><span style="color:#339933;">;</span>addView<span>(</span>content<span>)</span><span style="color:#339933;">;</span><span> </span><span>}</span><span> </span> <span> </span><span>if</span><span> </span><span>(</span>mView<span> </span><span style="color:#339933;">!=</span><span> </span>content<span>)</span><span> </span><span>{</span><span> </span>removeView<span>(</span>mView<span>)</span><span style="color:#339933;">;</span><span> </span>mView<span> </span><span style="color:#339933;">=</span><span> </span>content<span style="color:#339933;">;</span><span> </span><span>}</span><span> </span>...<span> </span><span>}</span>  

remoteViews.apply創建了實際的View,下面代碼可以看出:

  1. public View apply<SPAN>(</SPAN>Context context<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN>ViewGroup parent<SPAN>)</SPAN><SPAN> </SPAN><SPAN>{</SPAN><SPAN> </SPAN>View result<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">null</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>  Context c<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN>prepareContext<SPAN>(</SPAN>context<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>  Resources r<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>c.<SPAN style="COLOR: #202020">getResources</SPAN><SPAN>(</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>LayoutInflater inflater<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN>(</SPAN>LayoutInflater<SPAN>)</SPAN><SPAN> </SPAN>c .<SPAN style="COLOR: #202020">getSystemService</SPAN><SPAN>(</SPAN>Context.<SPAN style="COLOR: #202020">LAYOUT_INFLATER_SERVICE</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>  inflater<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN>inflater.<SPAN style="COLOR: #202020">cloneInContext</SPAN><SPAN>(</SPAN>c<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>inflater.<SPAN style="COLOR: #202020">setFilter</SPAN><SPAN>(</SPAN>this<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>  result<SPAN> </SPAN><SPAN style="COLOR: #339933">=</SPAN><SPAN> </SPAN>inflater.<SPAN style="COLOR: #202020">inflate</SPAN><SPAN>(</SPAN>mLayoutId<SPAN style="COLOR: #339933">,</SPAN>parent<SPAN style="COLOR: #339933">,</SPAN><SPAN> </SPAN><SPAN style="COLOR: #000000; FONT-WEIGHT: bold">false</SPAN><SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN>  performApply<SPAN>(</SPAN>result<SPAN>)</SPAN><SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN> <SPAN> </SPAN><SPAN>return</SPAN><SPAN> </SPAN>result<SPAN style="COLOR: #339933">;</SPAN><SPAN> </SPAN><SPAN>}</SPAN>  
  1. public View apply<span>(</span>Context context<span style="color:#339933;">,</span><span> </span>ViewGroup parent<span>)</span><span> </span><span>{</span><span> </span>View result<span> </span><span style="color:#339933;">=</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">null</span><span style="color:#339933;">;</span><span> </span>  Context c<span> </span><span style="color:#339933;">=</span>prepareContext<span>(</span>context<span>)</span><span style="color:#339933;">;</span><span> </span>  Resources r<span> </span><span style="color:#339933;">=</span><span> </span>c.<span style="color:#202020;">getResources</span><span>(</span><span>)</span><span style="color:#339933;">;</span><span> </span>LayoutInflater inflater<span> </span><span style="color:#339933;">=</span><span>(</span>LayoutInflater<span>)</span><span> </span>c .<span style="color:#202020;">getSystemService</span><span>(</span>Context.<span style="color:#202020;">LAYOUT_INFLATER_SERVICE</span><span>)</span><span style="color:#339933;">;</span><span> </span>  inflater<span> </span><span style="color:#339933;">=</span>inflater.<span style="color:#202020;">cloneInContext</span><span>(</span>c<span>)</span><span style="color:#339933;">;</span><span> </span>inflater.<span style="color:#202020;">setFilter</span><span>(</span>this<span>)</span><span style="color:#339933;">;</span><span> </span>  result<span> </span><span style="color:#339933;">=</span><span> </span>inflater.<span style="color:#202020;">inflate</span><span>(</span>mLayoutId<span style="color:#339933;">,</span>parent<span style="color:#339933;">,</span><span> </span><span style="color:#000000;FONT-WEIGHT: bold">false</span><span>)</span><span style="color:#339933;">;</span><span> </span>  performApply<span>(</span>result<span>)</span><span style="color:#339933;">;</span><span> </span> <span> </span><span>return</span><span> </span>result<span style="color:#339933;">;</span><span> </span><span>}</span>  

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<Context, WeakReference<AppWidgetManager>> 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             }
215             WeakReference<AppWidgetManager> 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     }
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;
 
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         }
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     }
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     }
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<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
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         }
120         final int N = updatedIds.length;
121         for (int i=0; i<N; i++) {
122             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();
2006             switch (which) {
2007                 case AddAdapter.ITEM_SHORTCUT: {
2008                     // Insert extra item to handle picking application
2009                     pickShortcut();
2010                     break;
2011                 }
2013                 case AddAdapter.ITEM_APPWIDGET: {
2014                     int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
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<PickAdapter.Item> items) {
83         final Bundle extras = getIntent().getExtras();
84         
85         // get and validate the extras they gave us
86         ArrayList<AppWidgetProviderInfo> customInfo = null;
87         ArrayList<Bundle> 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             }
95             int customInfoSize = customInfo.size();
96             for (int i=0; i<customInfoSize; i++) {
97                 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             }
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             }
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             }
120             for (int i=0; i<customExtrasSize; i++) {
121                 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         }
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      * <p>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      * <p>
143      * The intent will contain the following extras:
144      * <table>
145      *   <tr>
146      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
147      *     <td>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.</td>
150      *  </tr>
151      * </table>
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);
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);
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);
883         if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
885         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
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);
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         }
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];
903         LauncherModel.addItemToDatabase(this, launcherInfo,
904                 LauncherSettings.Favorites.CONTAINER_DESKTOP,
905                 mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
907         if (!mRestoring) {
908             mDesktopItems.add(launcherInfo);
910             // Perform actual inflation because we're live
911             launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
913             launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
914             launcherInfo.hostView.setTag(launcherInfo);
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;
96         if (item.container == -1) return;
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. <com.android.launcher.CellLayout
  2. ... ...
  3. launcher:shortAxisCells="4"
  4. launcher:longAxisCells="4"
  5. ... ...
  6. />

以上表示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. ... ...

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章