Android桌面Launcher源码浅析

Android启动过程-万字长文(Android14)中介绍了Android系统的启动过程,本篇文章将继续介绍桌面应用Launcher。

一、Launcher介绍

  • Android启动过程-万字长文(Android14)中提到Launcher是Android系统启动后,由SystemServerActivity Manager Service (AMS)加载的第一个应用程序
  • Launcher又被称为桌面程序,负责Android桌面的启动和管理
  • 用户使用的应用程序(App)都是通过Launcher来启动的

二、下载及编译

2.1 下载

shell 复制代码
git checkout android14-release

2.2 编译

使用AndroidStudio编译下载好的Launcher3工程

编译过程中遇到问题及解决方案可以参考以下博客:

三、源码解析

3.1 AndroidManifest.xml

在项目根目录的AndroidManifest.xml,定义了Launcher做为桌面程序的属性:

xml 复制代码
<application>
    <activity
        android:name="com.android.launcher3.Launcher"
        android:launchMode="singleTask">
        <intent-filter>
            <category android:name="android.intent.category.HOME" />
        </intent-filter>
    </activity>
</application>
  • android.intent.category.HOME : 告诉系统这是一个启动器(Launcher)应用程序,系统在初始化完成后会通过ActivityTaskManagerServicegetHomeIntent方法获取和启动桌面程序。具体可参见Android启动过程-万字长文(Android14)
  • 开发人员也可以自己开发一个桌面程序(如微软桌面),用户安装完成后,可以在系统设置中修改默认启动的桌面程序

3.2 Launcher.java

Launcher.java是Launcher的启动页面,负责资源初始化和桌面UI创建

3.2.1 onCreate方法

java 复制代码
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 获取 LauncherAppState 实例和模型
    LauncherAppState app = LauncherAppState.getInstance(this);
    mModel = app.getModel();
    
    // 初始化不变的设备配置文件
    InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
    initDeviceProfile(idp);
    idp.addOnChangeListener(this);

    // 获取共享首选项和图标缓存
    mSharedPrefs = LauncherPrefs.getPrefs(this);
    mIconCache = app.getIconCache();

    // 创建无障碍代理
    mAccessibilityDelegate = createAccessibilityDelegate();

    // 初始化拖动控制器
    initDragController();
    
    // 创建所有应用程序控制器
    mAllAppsController = new AllAppsTransitionController(this);
    
    // 创建状态管理器
    mStateManager = new StateManager<>(this, NORMAL);

    // 创建引导首选项
    mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);

    // 设置视图
    setupViews();

    // 初始化Widget
    mAppWidgetManager = new WidgetManagerHelper(this);
    mAppWidgetHolder = createAppWidgetHolder();
    mAppWidgetHolder.startListening();

    // 设置内容视图
    setContentView(getRootView());
    ComposeInitializer.initCompose(this);

}

3.2.2 setupViews方法

java 复制代码
protected void setupViews() {
    // 创建根视图
    inflateRootView(R.layout.launcher);

    // 获取拖动层和焦点处理器
    mDragLayer = findViewById(R.id.drag_layer);
    mFocusHandler = mDragLayer.getFocusIndicatorHelper();
    
    // 获取工作区、总览面板和Hotseat
    mWorkspace = mDragLayer.findViewById(R.id.workspace);
    mWorkspace.initParentViews(mDragLayer);
    mOverviewPanel = findViewById(R.id.overview_panel);
    mHotseat = findViewById(R.id.hotseat);
    // 将工作区设置为Hotseat
    mHotseat.setWorkspace(mWorkspace);

    // 设置拖动层
    mDragLayer.setup(mDragController, mWorkspace);

    // 设置工作区
    mWorkspace.setup(mDragController);
    // 在工作区绑定之前,确保我们将壁纸偏移锁定到默认状态,否则在RTL中我们将更新错误的偏移量
    mWorkspace.lockWallpaperToDefaultPage();
    mWorkspace.bindAndInitFirstWorkspaceScreen();
    mDragController.addDragListener(mWorkspace);

    // 获取搜索/删除/卸载栏
    mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);

    // 设置应用程序视图
    mAppsView = findViewById(R.id.apps_view);
    mAppsView.setAllAppsTransitionController(mAllAppsController);

    // 设置拖动控制器(拖动目标必须按优先级的相反顺序添加)
    mDropTargetBar.setup(mDragController);
    mAllAppsController.setupViews(mScrimView, mAppsView);

    // 如果启用了点分页,则设置工作区的分页指示器
    if (SHOW_DOT_PAGINATION.get()) {
        mWorkspace.getPageIndicator().setShouldAutoHide(true);
        mWorkspace.getPageIndicator().setPaintColor(
                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)
                        ? Color.BLACK
                        : Color.WHITE);
    }
}
  • Workspace:工作区,也是我们常说的桌面区域,包括搜索框,桌面,壁纸
  • AppsView:应用程序列表
  • Widget:小组件

三、Workspace、AppsView和Widget示例

3.1 Workspace(工作区)

  • 结构说明

3.2 AppsView(应用程序视图)

3.3 Widget(小组件)

四、点击App图标的事件响应

4.1 触发ItemClickHandler的onClick方法

  • ItemClickHandler负责处理桌面应用图标的点击事件。
  • 桌面图标的点击事件最终会触发ItemClickHandleronClick方法
  • onClick 方法最终会触发startAppShortcutOrInfoActivity方法
java 复制代码
/**
 * Class for handling clicks on workspace and all-apps items
 */
public class ItemClickHandler {
    private static void onClick(View v) {
        startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
    }
    
    // 通知launcher启动Activity
    private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
        launcher.startActivitySafely(v, intent, item);
    }
}

4.2 Launcher通知系统启动App

Launcher.java的startActivitySafely方法中调用ActivityContext.java的startActivitySafely方法

java 复制代码
public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
    RunnableList result = super.startActivitySafely(v, intent, item);
}

ActivityContext.java的startActivitySafely方法中调用了

java 复制代码
public interface ActivityContext {
        default RunnableList startActivitySafely(
            View v, Intent intent, @Nullable ItemInfo item) {
            if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            }
        }
        
        default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
            if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
                    // 通过快捷方式启动
                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
                } else {
                    // 普通方式启动,应用程序走这个分支
                    ((Context) this).startActivity(intent, optsBundle);
                }
        }
}

Android 应用快捷方式(Shortcut)官方文档

最终通过frameworks/base/core/java/android/app/Activity.java 源码地址中的startActivity方法启动了对应的应用程序。

相关推荐
安东尼肉店1 小时前
Android compose屏幕适配终极解决方案
android
2501_916007472 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun3 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户2018792831677 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子7 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜82277 小时前
安卓接入Max广告源
android
齊家治國平天下7 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO7 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel7 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢7 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱