launcher,也就是Android的桌面應用程序。下圖是我正在使用的魅族手機的launcher應用程序:
接下來我們要開發一個自己的launcher,使其替代系統的默認launcher。
怎樣使我們的應用程序成為一個launcher?
首先我們要有一個自己的Android應用,在這裡,我使用最簡單的應用程序Hello,
使用eclipse創建Android項目我這裡就省略了,直接上圖
來看看我的AndroidManifest.xml
view plaincopy
-
- android:versionCode="1"
- android:versionName="1.0">
-
- android:minSdkVersion="7"
- android:targetSdkVersion="7"/>
-
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme">
- android:name="com.example.hello.MainActivity"
- android:label="@string/app_name">
-
-
-
-
-
-
-
我們知道,一個應用程序可以有多個Activity,每個Activity是同級別的。那麼在啟動程序時,最先啟動哪個Activity呢?有些程序可能需要顯示在程 序列表裡,有些不需要。怎麼定義呢?android.intent.action.MAIN決定應用程序最先啟動的Activity ,android.intent.category.LAUNCHER決定應用程序是否顯示在程序列表裡。Main和LAUNCHER同時設定才有意義,如果有多個同級的Activity都有過濾器
則只有最前面的Activity的 有 效,啟動該程序時,執行的是該Activity。且在程序列表中有多個圖標,這些Activity都在程序列表中顯示,該Application有多個入 口,執行不同的Activity,但是整個程序的主入口(整個程序最先運行的那個activity)只有最先定義的那個Activity。
如 果一個應用沒有LAUNCHER則該apk仍能安裝到設備上,但是在主程序圖中看不到。如果給那個Activity 設定了LAUNCHER,且同時設定了Main,則這個Activity就可出現在程序圖中;如果沒有Main,則不知啟動哪個Activity,故也不 會有圖標出現。
那如果我們要把一個應用程序做為桌面應用程序,該怎麼辦呢?
如果了解Android的啟動流程的同學都知道,Zygote啟動SystemServer,SystemServer的main函數開始啟動各種服務。 首先啟動init1,然後啟動init2.init1這個方法是被Zygote調用來初始化系統的,init1會啟動native的服務如SurfaceFlinger,AudioFlinger等等,這些工作做完以後會回調init2來啟動Android的service。
view plaincopy
- publicstaticfinalvoidinit2(){
- 501Log.i(TAG,"EnteredtheAndroidsystemserver!");
- 502Threadthr=newServerThread();
- 503thr.setName("android.server.ServerThread");
- 504thr.start();
- 505}
init2中啟動ServerThread線程,ServerThread中啟動了一系列的服務,比如ActivityManagerService,EntropyService等等。
當這些服務起來以後,開始 ((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady() 在systemReady後開始開始啟動Launcher。
frameworks\base\services\Java\com\android\server\am\ActivityManagerService.java
view plaincopy
- 8422publicvoidsystemReady(finalRunnablegoingCallback){
- 8423//Inthesimulator,startRunningwillneverhavebeencalled,which
- 8424//normallysetsafewcrucialvariables.Doithereinstead.
- .........................
- 8594resumeTopActivityLocked(null);
- }
frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
view plaincopy
- 2576privatefinalbooleanresumeTopActivityLocked(HistoryRecordprev){
- 2577//Findthefirstactivitythatisnotfinishing.
- 2578HistoryRecordnext=topRunningActivityLocked(null);
- 2579
- 2580//Rememberhowwe'llprocessthispause/resumesituation,andensure
- 2581//thatthestateisresethoweverwewindupproceeding.
- 2582finalbooleanuserLeaving=mUserLeaving;
- 2583mUserLeaving=false;
- 2584
- 2585if(next==null){
- 2586//Therearenomoreactivities!Let'sjuststartupthe
- 2587//Launcher...
- 2588returnstartHomeActivityLocked();
- 2589}
frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
view plaincopy
- 2457privatebooleanstartHomeActivityLocked(){
- 2458if(mFactoryTest==SystemServer.FACTORY_TEST_LOW_LEVEL
- 2459&&mTopAction==null){
- 2460//Wearerunninginfactorytestmode,butunabletofind
- 2461//thefactorytestapp,sojustsitarounddisplayingthe
- 2462//errormessageanddon'ttrytostartanything.
- 2463returnfalse;
- 2464}
- 2465Intentintent=newIntent(
- 2466mTopAction,
- 2467mTopData!=null?Uri.parse(mTopData):null);
- 2468intent.setComponent(mTopComponent);
- 2469if(mFactoryTest!=SystemServer.FACTORY_TEST_LOW_LEVEL){
- 2470intent.addCategory(Intent.CATEGORY_HOME);
- 2471}
frameworks/base/core/java/android/content/Intent.java
view plaincopy
1881publicstaticfinalStringCATEGORY_HOME="android.intent.category.HOME";
view plaincopy
-
- 現在重新編譯我們的應用程序,把編譯生成的APK放到相應的目錄下,一般是/system/app,啟動開發板,我們可以看到在我們的LCD屏上面,要求用戶選擇launcher。
到這裡,我們不禁要想,如果我們從這裡彈出我們自己定制的Launcher,但同時不彈出選擇HOME的界面,我們也不希望用戶修改我們的home,比如我們的home上放了好多廣告,以及強制安裝的程序,不希望用戶把它干掉。
在這裡,我們就可以寫一個自己私有的filter選項,然後用這個選項來過濾HOME. 一般情況下我們使用Manifest中定義的
這裡我們有一種比較暴力的更改方法,就是把系統中原有的public static final String CATEGORY_HOME = "android.intent.category.HOME";
更改成public static final String CATEGORY_FS_HOME = "android.intent.category.FS_HOME";
然後修改和CATEGORY_HOME相關的所有的地方,都改成CATEGORY_FS_HOME.如果不知道修改哪些地方,可以使用如下命令去查找:
view plaincopy
grepCATEGORY_HOME-l*-R 查找到的文件大概有這些:view plaincopy
-
- android:versionCode="1"
- android:versionName="1.0">
-
- android:minSdkVersion="7"
- android:targetSdkVersion="7"/>
-
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme">
- android:name="com.example.hello.MainActivity"
- android:label="@string/app_name">
-
-
-
-
-
-
-
重新編譯我們的應用程序,放到我們開發板相應目錄下,就可以看到我們自己的Launcher了!