`

定制的Launcher成为系统中唯一的Launcher

阅读更多
轉自:http://www.eoeandroid.com/thread-32778-1-1.html
如果你要定制一个Android系统,你想用你自己的Launcher(Home)作主界面来替换Android自己的Home,而且不希望用户安装的Launcher来替换掉你的Launcher.
我们可以通过修改Framework来实现这样的功能。

这里以Android2.1的源代码为例来实际说明。

1)首先了解一下Android的启动过程。
  Android系统的启动先从Zygote开始启动,然后......(中间的过程就不说了).....一直到了SystemServer(framework)这个地方,看到这段代码:

      /**
     * This method is called from Zygote to initialize the system. This will cause the native
     * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
     * up into init2() to start the Android services.
     */
    native public static void init1(String[] args);

    public static void main(String[] args) {
        if (SamplingProfilerIntegration.isEnabled()) {
            SamplingProfilerIntegration.start();
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    SamplingProfilerIntegration.writeSnapshot("system_server");
                }
            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
        }

        // The system server has to run all of the time, so it needs to be
        // as efficient as possible with its memory usage.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

        System.loadLibrary("android_servers");
        init1(args);
    }

    public static final void init2() {
        Log.i(TAG, "Entered the Android system server!");
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
    }
}

从SystemServer的main函数开始启动各种服务。
首先启动init1,然后启动init2.
从上面的注释可以看到:init1这个方法时被Zygote调用来初始化系统的,init1会启动native的服务如SurfaceFlinger,AudioFlinger等等,这些工作做完以后会回调init2来启动Android的service。

这里我们主要来关注init2的过程。
init2中启动ServerThread线程,
ServerThread中启动了一系列的服务,比如这些:

ActivityManagerService
EntropyService
PowerManagerService
TelephonyRegistry
PackageManagerService
AccountManagerService
BatteryService
HardwareService
Watchdog
SensorService
BluetoothService
StatusBarService
ClipboardService
InputMethodManagerService
NetStatService
ConnectivityService
AccessibilityManagerService
NotificationManagerService
MountService
DeviceStorageMonitorService
LocationManagerService
SearchManagerService
FallbackCheckinService
WallpaperManagerService
AudioService
BackupManagerService
AppWidgetService

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

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

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

我们可以通过这样来实现:

2) 定义一个私有的filter选项,然后用这个选项来过滤HOME.
   一般情况下我们使用Manifest中定义的<category android:name="android.intent.category.HOME"来过滤的,我们现在增加一个私有的HOME_FIRST过滤。

     在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加两行代码

    //lixinso:添加CATEGORY_HOME_FIRST
    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
    public static final String CATEGORY_HOME_FIRST = "android.intent.category.HOME_FIRST";

3)修改和CATEGORY_HOME相关的所有的地方,都改成HOME_FIRST,主要是framework中的这几个地方:

    frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中
    //intent.addCategory(Intent.CATEGORY_HOME);
    改成intent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso:
    //if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
    改成if (r.intent.hasCategory(Intent.CATEGORY_HOME_FIRST)) { //lixinso: Intent.CATEGORY_HOME -> Intent.CATEGORY_HOME_FIRST

   frameworks/base/services/java/com/android/server/am/HistoryRecorder.java中
   // _intent.hasCategory(Intent.CATEGORY_HOME) &&
   改成 _intent.hasCategory(Intent.CATEGORY_HOME_FIRST) && //lixinso: Intent.CATEGORY_HOME->Intent.CATEGORY_HOME_FIRST

   frameworks/policies/base/mid/com/android/internal/policy/impl/MidWindowManager.java中
   //mHomeIntent.addCategory(Intent.CATEGORY_HOME);
   改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

  frameworks/policies/base/mid/com/android/internal/policy/impl/RecentApplicationsDialog.java中
   //new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
   改成 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso

  frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中
   //mHomeIntent.addCategory(Intent.CATEGORY_HOME);
   改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

  frameworks/policies/base/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java中
   //ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
   改成 ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso



4) 写一个自己的Launcher.
   可以参考android sample中的Launcher,或者android源代码中的 /packages/apps/Launcher 来写。
   在Launcher中标记其是不是Launcher的最关键的代码时Manifest中的filter:android:name="android.intent.category.HOME"
   现在我们定义了自己的filter,那么,我们在我们自己写的Launcher中将Manifest改为:
    <application  android:process="android.process.acore3" android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".FirstAppActivity"
                  android:label="@string/app_name">
            <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME_FIRST" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY" />
            </intent-filter>
        </activity>
    </application>

然后将编译好的apk放到/out/target/product/generic/system/app目录下。

5)将Android自带的Launcher删除掉,包括源代码(packages/apps/Launcher)和apk(/out/target/product/generic/system/app/Launcher.apk)。

6)
做完这些工作,就可以重新编译Android了,我们可以编译修改过的几个相关的包。
如果之前编译过了Android源码,可以用mmm命令来编译部分的改动。
这里需要这样编译:

$ . build/envsetup.sh
$ mmm frameworks/base
$ mmm frameworks/base/services/java
$ mmm frameworks/policies/base/mid
$ mmm frameworks/policies/base/phone

7)
编译完成后重新生成img文件。
$ make snod

8) 现在可以启动Android模拟器来看效果了。
首先设置环境变量:
$ export ANDROID_PRODUCT_OUT= ./out/target/product/generic
然后切换到
$ cd ./out/host/linux-x86/bin
运行
$ ./emulator

这样我们启动的模拟器里面用的image就是我们刚才编译好的自己定制的东西了。
从模拟器上可以看到启动的Launcher是我们自己的Launcher,不会出现默认的Launcher了,也不会出现选择界面。

9)我们再验证一下,如果用户装上了一个其他的Launcher(Home)会怎么样。
  从网上找一个一般的Launcher或者自己写一个一般的Launcher装上去,重新启动,不会出现选择界面。
  按HOME键也不会出来两个HOME来选择。


这样我们就牢牢控制了用户的桌面。
只有我们自己定制的HOME才能装上。 这对于定制Android设备的厂商很有用处。

原文在我的blog:http://blog.csdn.net/lixinso/archive/2010/09/08/5871862.aspx
欢迎大家来一起讨论Android开发,我的email: lixinso [at] gmail [dot] com
分享到:
评论

相关推荐

    让你定制的Launcher成为系统中唯一的Launcher.txt

    ### 让你定制的Launcher成为系统中唯一的Launcher 在Android系统中,Launcher(启动器)是用户与系统交互的重要界面之一。它不仅负责显示应用程序图标、桌面小部件等元素,还承担着启动应用的重要职责。为了让...

    Android 4.0 Launcher2 源码 Eclipse版(已修改包名,不冲突系统桌面)

    在 Android 系统中,每个应用都有自己的唯一标识(包名),如果两个应用使用相同的包名,系统将无法区分它们,可能会导致运行时错误。 6. **Eclipse 版**: 提供的是 Eclipse 开发环境下的源码,这意味着开发者可以...

    一种加快定制android系统桌面快捷图标的方法.docx

    这些信息是每个应用程序在系统中的唯一标识,它们是连接应用与桌面快捷方式的关键。 随后,将获取到的包名和类名信息写入到Android系统的一个特定的XML文件中。XML文件是一种结构化的数据存储格式,便于程序读取和...

    AnderWeb-android_packages_apps_Launcher-4458ee4.zip

    "Launcher"在Android系统中通常指的是桌面启动器,它是用户界面的核心部分,允许用户打开应用、管理屏幕快捷方式和小部件。4458ee4可能是该版本的标识符或Git提交哈希,用于追踪代码的特定版本。 在深入讨论之前,...

    AnderWeb-android_packages_apps_Launcher-4458ee4_Android.rar

    这里提到的"android_packages_apps_Launcher"表明这是Android系统中的一个应用包,专门用于启动器功能。 2. **启动器的定制**:自定义启动器通常允许用户自定义主屏幕的图标、布局、小部件、过渡效果等。它们可能还...

    TravPRO Mobile Launcher-crx插件

    在【压缩包子文件的文件名称列表】中,我们看到唯一的文件名是"TravPRO_Mobile_Launcher.crx",这是Chrome浏览器扩展的典型文件格式。CRX文件包含了扩展的所有代码和资源,用户只需将这个文件拖放到Chrome浏览器中,...

    适用于Google:trade_mark:的应用启动器定制器「App Launcher Customizer for Google:trade_mark:」-crx插件

    唯一的缺点是您无法自定义应用启动器中显示的快捷方式。 这就是这个扩展插件的用途。它允许您自定义应用程序启动器,并添加250多个Google快捷方式。并不限于这250个Google快捷方式;该扩展还可以让你创建自定义的快捷...

    GUI Launcher for MPlayer-开源

    此外,它唯一依赖的外部库是Qt4,这是一个功能强大且广泛使用的C++图形用户界面库,提供了丰富的控件和功能,使得开发者能够快速构建美观且高效的用户界面。 在源代码中,我们可以看到以下几个关键文件: 1. `...

    类的加载器资料.zip

    这个模型保证了Java核心类库的唯一性,避免用户自定义类覆盖系统类。 3. **实际加载**:如果父加载器无法加载,当前加载器才会尝试加载。它会根据类名找到对应的.class文件,然后进行字节码验证、解析和初始化等步骤...

    Kustom KLWP 3.38b903016.apk

    其他一些人可能有问题,现在唯一已知问题的发射器是GO Launcher(我们无法解决这个问题)。 Smart Launcher 3 v3.26.010破解APK就在这里![最新] OK Launcher Prime - 奥利奥启动器与Android™O 8.0 v2.0破解APK ...

    高仿小米电视luncher控件.rar

    在实际使用中,开发者需要具备一定的Android开发知识,包括Java或Kotlin编程、Android SDK、XML布局理解以及对Android系统服务和组件的了解。通过研究和修改这些代码,开发者可以定制自己的电视应用界面,或者改进...

    A83T Android快速移植指南

    以上内容概括了“A83T Android快速移植指南”中的关键知识点和技术细节,涵盖了从系统定制到模块配置、再到个性化设置的各个方面。这对于理解和操作基于A83T平台的Android设备具有重要的参考价值。

    安卓Android源码——隐藏安装包图标使用其他应用启动本应用.zip

    在安卓(Android)系统中,隐藏安装包的图标并使用其他应用启动本应用是一种常见的定制化需求,尤其在开发特定类型的App时,如系统服务或后台应用。这种做法可以让用户在主屏幕上看不到应用的图标,但依然可以通过...

    htc桌面天气实测可修改城市版

    1. **HTC 桌面环境**:HTC手机采用的定制化Android系统通常会有自家的桌面环境,这包括启动器(Launcher)、小部件和其他个性化设置。这些桌面环境通常会集成一些特色功能,比如天气显示。 2. **天气小部件**:天气...

    Java类加载原理解析

    此外,还存在一种特殊的类加载器——**线程上下文类加载器(Thread Context ClassLoader)**,它允许在特定线程中定制类加载行为,常用于插件系统和容器环境。 **双亲委派机制** Java 类加载的默认策略是双亲委派...

    创建快捷方式

    在Android系统中,创建应用快捷方式是为用户提供更便捷访问特定功能或Activity的方式。通过创建快捷方式,用户可以在主屏幕上直接点击图标,快速启动应用程序的某个特定页面,而无需每次都打开整个应用。以下是对这...

    Android发送通知Notification

    在Android开发中,发送通知是将消息展示给用户的重要手段,尤其当应用在后台...为了提高用户体验,开发者还应考虑通知的可定制性,如声音、振动和渠道设置,以及遵循Android系统的最佳实践,确保通知的及时性和重要性。

    给Android的应用换个图标(桌面快捷图标)sShortcut

    首先,我们需要理解Android系统中快捷方式(Shortcut)的概念。在Android上,快捷方式是一种指向应用程序特定功能的接口,用户可以通过长按应用图标或通过启动器(Launcher)创建。在API 25及更高版本中,Android...

    TabHost使用方法

    虽然可以直接使用 Android 系统提供的默认布局文件,但为了增加灵活性和可定制性,通常会自己定义布局文件。 3. **获取 TabHost 容器** ```java TabHost tabHost = getTabHost(); ``` - **说明**:通过 `...

Global site tag (gtag.js) - Google Analytics