Android更改桌面应用程序launcher的两种方式

launcher,也就是Android的桌面应用程序。下图是我正在使用的魅族手机launcher应用程序:


   接下来我们要开发一个自己的launcher,使其替代系统的默认launcher
怎样使我们的应用程序成为一个launcher


   首先我们要有一个自己的Android应用,在这里,我使用最简单的应用程序Hello,

使用eclipse创建Android项目我这里就省略了,直接上图



   来看看我的AndroidManifest.xml


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.hello"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="7"  
  9.         android:targetSdkVersion="7" />  
  10.   
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@style/AppTheme" >  
  16.         <activity  
  17.             android:name="com.example.hello.MainActivity"  
  18.             android:label="@string/app_name" >  
  19.             <intent-filter>  
  20.                 <action android:name="android.intent.action.MAIN" />  
  21.   
  22.                 <category android:name="android.intent.category.LAUNCHER" />  
  23.             </intent-filter>  
  24.         </activity>  
  25.     </application>  
  26.   
  27. </manifest>  

   我们知道,一个应用程序可以有多个Activity,每个Activity是同级别的。那么在启动程序时,最先启动哪个Activity呢?有些程序可能需要显示在程 序列表里,有些不需要。怎么定义呢?android.intent.action.MAIN决定应用程序最先启动的Activity ,android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。Main和LAUNCHER同时设定才有意义,如果有多个同级的Activity都有过滤器
<intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
   则只有最前面的Activity的 <action android:name="android.intent.action.MAIN" /> 有 效,启动该程序时,执行的是该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。


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static final void init2() {  
  2. 501         Log.i(TAG, "Entered the Android system server!");  
  3. 502         Thread thr = new ServerThread();  
  4. 503         thr.setName("android.server.ServerThread");  
  5. 504         thr.start();                                                                              
  6. 505     }  

   init2中启动ServerThread线程,ServerThread中启动了一系列的服务,比如ActivityManagerService,EntropyService等等。

   当这些服务起来以后,开始  ((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady() 在systemReady后开始开始启动Launcher。

frameworks\base\services\Java\com\android\server\am\ActivityManagerService.java

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 8422     public void systemReady(final Runnable goingCallback) {  
  2. 8423         // In the simulator, startRunning will never have been called, which  
  3. 8424         // normally sets a few crucial variables. Do it here instead.   
  4.         .........................  
  5. 8594           resumeTopActivityLocked(null);  
  6.      }  


frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 2576     private final boolean resumeTopActivityLocked(HistoryRecord prev) {                         
  2. 2577         // Find the first activity that is not finishing.  
  3. 2578         HistoryRecord next = topRunningActivityLocked(null);  
  4. 2579   
  5. 2580         // Remember how we'll process this pause/resume situation, and ensure  
  6. 2581         // that the state is reset however we wind up proceeding.  
  7. 2582         final boolean userLeaving = mUserLeaving;  
  8. 2583         mUserLeaving = false;  
  9. 2584   
  10. 2585         if (next == null) {  
  11. 2586             // There are no more activities!  Let's just start up the  
  12. 2587             // Launcher...  
  13. 2588             return startHomeActivityLocked();  
  14. 2589         }  

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 2457     private boolean startHomeActivityLocked() {                                                 
  2. 2458         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL  
  3. 2459                 && mTopAction == null) {  
  4. 2460             // We are running in factory test mode, but unable to find  
  5. 2461             // the factory test app, so just sit around displaying the  
  6. 2462             // error message and don't try to start anything.  
  7. 2463             return false;  
  8. 2464         }  
  9. 2465         Intent intent = new Intent(  
  10. 2466             mTopAction,  
  11. 2467             mTopData != null ? Uri.parse(mTopData) : null);  
  12. 2468         intent.setComponent(mTopComponent);  
  13. 2469         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {  
  14. 2470             intent.addCategory(Intent.CATEGORY_HOME);  
  15. 2471         }  


frameworks/base/core/java/android/content/Intent.java

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 1881     public static final String CATEGORY_HOME = "android.intent.category.HOME";    

     根据上面代码可知,在寻找Launcher的时候是根据HOME的filter(在Manifest中定义的<category android:name=”android.intent.category.HOME” />)来过滤。 然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了HOME,那就会弹出来一个列表供用户选择。 

   既然如此,我们现在就可以更改我们的AndroidManifest.xml来安装自己的HOME。所以我们只需在AndroidManifest.xml添加两行代码:

   

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <category android:name="android.intent.category.HOME" />    
  2. <category android:name="android.intent.category.DEFAULT" />    
   现在重新编译我们的应用程序,把编译生成的APK放到相应的目录下,一般是/system/app,启动开发板,我们可以看到在我们的LCD屏上面,要求用户选择launcher。


   到这里,我们不禁要想,如果我们从这里弹出我们自己定制的Launcher,但同时不弹出选择HOME的界面,我们也不希望用户修改我们的home,比如我们的home上放了好多广告,以及强制安装的程序,不希望用户把它干掉。 

   在这里,我们就可以写一个自己私有的filter选项,然后用这个选项来过滤HOME. 一般情况下我们使用Manifest中定义的<category android:name="android.intent.category.HOME"来过滤的,我们现在增加一个私有的FS_HOME过滤。

   这里我们有一种比较暴力的更改方法,就是把系统中原有的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.如果不知道修改哪些地方,可以使用如下命令去查找:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. grep  CATEGORY_HOME  -l  *  -R  
查找到的文件大概有这些:


将上述文件中和CATEGORY_HOME相关的所有的地方,都改成CATEGORY_FS_HOME即可。


   然后,我们可以把之前的应用程序hello的AndroidManifest.xml更改如下:


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.hello"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="7"  
  9.         android:targetSdkVersion="7" />  
  10.   
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@style/AppTheme" >  
  16.         <activity  
  17.             android:name="com.example.hello.MainActivity"  
  18.             android:label="@string/app_name" >  
  19.             <intent-filter>  
  20.                 <action android:name="android.intent.action.MAIN" />  
  21.                  <category android:name="android.intent.category.FS_HOME" />   
  22.                 <category android:name="android.intent.category.DEFAULT" />                                                                        <category android:name="android.intent.category.MONKEY" />   
  23.             </intent-filter>  
  24.         </activity>  
  25.     </application>  
  26.   
  27. </manifest>  

重新编译我们的应用程序,放到我们开发板相应目录下,就可以看到我们自己的Launcher了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值