http://blog.csdn.net/mdx20072419/article/details/9632779/

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

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

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

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

来看看我的AndroidManifest.xml

  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. <uses-sdk
  7. android:minSdkVersion="7"
  8. android:targetSdkVersion="7" />
  9. <application
  10. android:allowBackup="true"
  11. android:icon="@drawable/ic_launcher"
  12. android:label="@string/app_name"
  13. android:theme="@style/AppTheme" >
  14. <activity
  15. android:name="com.example.hello.MainActivity"
  16. android:label="@string/app_name" >
  17. <intent-filter>
  18. <action android:name="android.intent.action.MAIN" />
  19. <category android:name="android.intent.category.LAUNCHER" />
  20. </intent-filter>
  21. </activity>
  22. </application>
  23. </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。

  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

  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

  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

  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

  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添加两行代码:

  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.如果不知道修改哪些地方,可以使用如下命令去查找:

  1. grep  CATEGORY_HOME  -l  *  -R

查找到的文件大概有这些:


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

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

  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. <uses-sdk
  7. android:minSdkVersion="7"
  8. android:targetSdkVersion="7" />
  9. <application
  10. android:allowBackup="true"
  11. android:icon="@drawable/ic_launcher"
  12. android:label="@string/app_name"
  13. android:theme="@style/AppTheme" >
  14. <activity
  15. android:name="com.example.hello.MainActivity"
  16. android:label="@string/app_name" >
  17. <intent-filter>
  18. <action android:name="android.intent.action.MAIN" />
  19. <category android:name="android.intent.category.FS_HOME" />
  20. <category android:name="android.intent.category.DEFAULT" />                                                                        <category android:name="android.intent.category.MONKEY" />
  21. </intent-filter>
  22. </activity>
  23. </application>
  24. </manifest>

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

Android设置默认Launcher

http://huamm.blog.51cto.com/5646020/1550305

当系统存在多个launcher时,若没有设置默认launcher,开机启动后会弹出提示框,罗列所有launcher,用户选择并设置了默认launcher后,按home键以及以后重启都会进入默认的launcher。

现在,我希望系统能直接就进入我设定的launcher而不是弹出框后选择然后设置

网上大部分的做法就是修改

1
packages/apps/Provision/src/com/android/DefaultActivity.java

1
frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

两个文件,给个相对比较好看一点的链接http://blog.csdn.net/z_guijin/article/details/8964890

我按照这个做不能达到预期的效果,

/////////////////////////////////////////添加内容////////////////////////////////////////

后期修改包名,发现开机自启动出现问题,然后弄了两天,终于差不多弄清楚了。果然,欠下的债迟早得还!

其实修改DefaultActivity.java就能够完成开机自启动,只是当时我的程序有问题,所以没有达到预期效果

当然下面修改ActivityManagerService.java也能完成开机自启动

这两者的区别在于
DefaultActivity.java只是在第一次启动时执行,如果修改了默认launcher后不可恢复

ActivityManagerService.java在每次启动时执行,每次都默认启动设定的launcher,当然,如果设定的launcher存在的话,设置其他的launcher为默认会无效,因为重新启动时setDefaultLauncher()会将当前默认launcher清除。只有在卸载了设定默认启动的launcher后才能设置其他launcher为默认启动.

//////////////////////////////////////////////////////////////////////////////////////////////////////////

修改多次搜索关键字,得到另一篇文章,大致看了下,感觉不会有效,但是已经绝望了就试了试,竟然解决了问题http://blog.csdn.net/jia4525036/article/details/18036765

这篇文章有借鉴之处,直接使用时会发现有些字段是上下文中没有的,故写下此文记录一下。

修改文件

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

添加一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    private void setDefaultLauncher() {  
        // get default component   
        String packageName = "com.coship.factorytest";//默认launcher包名
        String className = "com.coship.factorytest.MainActivity";////默认launcher入口
          
        IPackageManager pm = ActivityThread.getPackageManager();
         
        //判断指定的launcher是否存在
        if(hasApkInstalled(packageName)) {
         
            Slog.i(TAG, "defautl packageName = " + packageName + ", default className = " + className); 
                       
            //清除当前默认launcher 
            ArrayList<IntentFilter> intentList = new ArrayList<IntentFilter>();  
            ArrayList<ComponentName> cnList = new ArrayList<ComponentName>();  
            mContext.getPackageManager().getPreferredActivities(intentList, cnList, null);  
            IntentFilter dhIF = null;  
            for(int i = 0; i < cnList.size(); i++) {  
                dhIF = intentList.get(i);  
                if(dhIF.hasAction(Intent.ACTION_MAIN) && dhIF.hasCategory(Intent.CATEGORY_HOME)) {  
                    mContext.getPackageManager().clearPackagePreferredActivities(cnList.get(i).getPackageName());  
                }  
            }  
                       
            //获取所有launcher activity 
            Intent intent = new Intent(Intent.ACTION_MAIN);  
            intent.addCategory(Intent.CATEGORY_HOME);  
            List<ResolveInfo> list = new ArrayList<ResolveInfo>();  
            try {  
                list = pm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DEFAULT_ONLY);  
            }catch (RemoteException e) {  
                throw new RuntimeException("Package manager has died", e);  
            }   
            // get all components and the best match  
            IntentFilter filter = new IntentFilter();  
            filter.addAction(Intent.ACTION_MAIN);  
            filter.addCategory(Intent.CATEGORY_HOME);  
            filter.addCategory(Intent.CATEGORY_DEFAULT);  
            final int N = list.size();  
            Slog.d(TAG, "N:::::hyhyhyhy:::: = " + N);  
                     
            //设置默认launcher 
            ComponentName launcher = new ComponentName(packageName, className);  
 
            ComponentName[] set = new ComponentName[N];  
            int defaultMatch = 0;  
            for (int i = 0; i < N; i++) {  
                ResolveInfo r = list.get(i);  
                set[i] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name);  
                Slog.d(TAG, "r.activityInfo.packageName:::::hyhyhyhy:::: = " + r.activityInfo.packageName);
                Slog.d(TAG, "r.activityInfo.name:::::hyhyhyhy:::: = " + r.activityInfo.name);
                if(launcher.getClassName().equals(r.activityInfo.name)) {
                    defaultMatch = r.match;
                }
            }  
                     
            try {  
                pm.addPreferredActivity(filter, defaultMatch, set, launcher);
            catch (RemoteException e) {  
                throw new RuntimeException("com.coship.factorytest.MainActivity : Package manager has died", e);  
            }   
             
             
        }//end if
         
    }  
 
    private static boolean hasApkInstalled(String pkgname) {
 
        try {
            mSelf.mContext.getPackageManager().getPackageInfo(pkgname,0);
        catch(Exception e) {
            Slog.d(TAG, "PackageManager.NameNotFoundException: = " + e.getMessage());
            return false;
        }
        return true;
    }

然后在ActivityManagerService类中的

1
boolean startHomeActivityLocked()

方法第一行调用上面添加的

1
setDefaultLauncher()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  boolean startHomeActivityLocked() {
     
        if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
 
///////////////////////////////////////////
        setDefaultLauncher();
///////////////////////////////////////////
         
        Intent intent = new Intent(
            mTopAction,
            mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        ActivityInfo aInfo =
            intent.resolveActivityInfo(mContext.getPackageManager(),
                    STOCK_PM_FLAGS);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mMainStack.startActivityLocked(null, intent, nullnull0, aInfo,
                        nullnull000falsefalsenull);
            }
        }
         
         
        return true;
    }

添加后的方法全部内容如上,重新编译android,烧录,开机就能够自动进入自定义的launcher

可以通过系统设置取消该launcher的默认设置,取消之后按home键会弹出launcher选择提示框

1
frameworks\base\core\java\com\android\internal\app\ResolverActivity.java

ResolverActivity类就是选择打开方式的弹出框

Android更改桌面应用程序launcher的两种方式的更多相关文章

  1. 怎样在Android开发中FPS游戏实现的两种方式比较

    怎样在Android开发中FPS游戏实现的两种方式比较 如何用Android平台开发FPS游戏,其实现过程有哪些方法,这些方法又有哪些不同的地方呢?首先让我们先了解下什么是FPS 英文名:FPS (F ...

  2. [Android] Android ViewPager 中加载 Fragment的两种方式 方式(二)

    接上文: https://www.cnblogs.com/wukong1688/p/10693338.html Android ViewPager 中加载 Fragmenet的两种方式 方式(一) 二 ...

  3. [Android] Android ViewPager 中加载 Fragment的两种方式 方式(一)

    Android ViewPager 中加载 Fragmenet的两种方式 一.当fragment里面的内容较少时,直接 使用fragment xml布局文件填充 文件总数 布局文件:view_one. ...

  4. Android中H5和Native交互的两种方式

    Android中H5和Native交互的两种方式:http://www.jianshu.com/p/bcb5d8582d92 注意事项: 1.android给h5页面注入一个对象(WZApp),这个对 ...

  5. Android ActionBar Home按钮返回事件处理的两种方式

    今早无聊查看了一下android官方文档,最近对ActionBar很感兴趣,它确实对我们的日常开发起到了很便捷的作用. 对于通过点击ActionBar的Home按钮返回,以前我只知道有一种方式:也就是 ...

  6. 【转】android创建Popwindow弹出菜单的两种方式

    方法一的Activity package com.app.test02; import android.app.Activity; import android.os.Bundle; import a ...

  7. android 向serverGet和Post请求的两种方式,android向server发送文件,自己组装协议和借助第三方开源

    一个适用于Android平台的第三方和apache的非常多东西类似,仅仅是用于Android上 我在项目里用的是这个 https://github.com/loopj/android-async-ht ...

  8. Android中服务的生命周期与两种方式的区别

    服务的生命周期跟Activity的生命周期类似.但是生命周期甚至比你关注服务如何创建和销毁更重要,因为服务能够在用户不知情的情况下在后台运行. 服务的生命周期---从创建到销毁---可以被分为以下两个 ...

  9. 小程序-引用的两种方式:import和include

    import import可以在该文件中使用目标文件定义的template,如: 在mine.wxml中定义了一个叫item的template: <template name="ite ...

随机推荐

  1. ACCESS-关于DELPHI中操作ACCESS数据库中单精度数据的问题

    在近日几个帖子里面,和QQ群的讨论里面,我发现很多网友都遇到的问题都是因为不恰当地使用了单精度/双精度数值.因此想专门就这个话题谈一下. 单精度和双精度数值类型最早出现在C语言中(比较通用的语言里面) ...

  2. NGUI学习笔记(一):官方视频学习记录

    学习NGUI一直断断续续的,目前打算做一个总结的笔记. 我使用的是比较老的3.6.0版本. 1.使用NGUI,需要开启“Edit”->“Project Settings”->“Physic ...

  3. 【Away3D代码解读】(三):渲染核心流程(渲染)

    还是老样子,我们还是需要先简略的看一下View3D中render方法的渲染代码,已添加注释: //如果使用了 Filter3D 的话会判断是否需要渲染深度图, 如果需要的话会在实际渲染之前先渲染深度图 ...

  4. 从最近MySQL的优化工作想到的

    最近决定将以前同事写的存储过程查看一遍,寻找一些代码上写的不太好的地方,争取进行修改以后让这些过程达到一个很好的运行速度.下面是遇到的最多的几个问题. 我遇到了这样的一个SQL: select nam ...

  5. MinGW安装和使用总结

    0.前言 最近对开源编译平台和编译器产生了兴趣,借博客平台总结一些东西(包括minGW,eclipse,sourcery和GDB调试等内容).总感觉时间一长某些东西自己都会忘记,过段时间回头看看自己的 ...

  6. WinForm开发中针对TreeView控件改变当前选择节点的字体与颜色

    本文转载:http://www.cnblogs.com/umplatform/archive/2012/08/29/2660240.html 在B/S开发中,对TreeView控件要改变当前选中节点的 ...

  7. 补丁安装命令(WUSA)

    wusa windows6.1-kb2716513-x64.msu /quiet /norestart msxml4-kb2758694-enu.exe /quiet /norestart 安装.ms ...

  8. sql函数:汉字转换为拼音

    sql数据库自定义一个函数把下面代码写进去 功能是得到汉字拼音首字母create function fun_getPY(@str nvarchar(4000)) returns nvarchar(40 ...

  9. Aizu 2304 Reverse Roads 费用流

    Reverse Roads Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view ...

  10. yum -------包安装库

    elrepo:   http://elrepo.org/tiki/tiki-index.php CentOSPlus:    http://wiki.centos.org/zh/AdditionalR ...