保姆级教程:为 AOSP Android 14 的 Launcher3 添加一个自定义的 LauncherState(比如“专注模式”)
深度定制 AOSP Android 14 Launcher3实现专注模式状态全流程解析在 Android 系统深度定制领域Launcher3 作为系统主屏幕的核心组件其状态管理机制一直是开发者关注的焦点。本文将手把手带你实现一个官方未提供的专注模式状态让主屏幕在特定条件下自动切换为简约界面只保留必要的小部件和功能。1. 理解 LauncherState 架构设计Launcher3 的状态管理系统采用经典的状态模式State Pattern通过抽象基类LauncherState定义所有状态的公共接口而具体子类实现各自的特有行为。这种设计使得新增状态只需扩展基类无需修改现有状态逻辑。状态机的核心组件包括LauncherState抽象基类定义状态的公共属性和方法getWorkspaceScaleAndTranslation()控制工作区缩放和平移getOverviewScaleAndTranslation()控制概览界面的视觉表现getHotseatScaleAndTranslation()控制底部热区的变换getVisibleElements()决定哪些UI元素应该显示StateManager状态管理中枢负责维护当前状态处理状态切换逻辑管理状态过渡动画典型的视觉属性控制参数属性类型说明workspaceScalefloat工作区缩放比例 (0.8-1.2)workspaceTranslationYfloat工作区垂直位移 (像素)overviewScalefloat概览界面缩放比例hotseatAlphafloat热区透明度 (0-1)hotseatTranslationYfloat热区垂直位移hasBackdropboolean是否显示背景模糊效果2. 创建 FocusState 自定义状态类在src/com/android/launcher3/states目录下新建FocusState.java继承LauncherState并实现专注模式的特有行为public class FocusState extends LauncherState { private static final int STATE_FLAGS FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_HAS_SYSTEM_UI_SCRIM; public FocusState(int id) { super(id, LAUNCHER_STATE_CUSTOM, STATE_FLAGS); } Override public float getWorkspaceScaleAndTranslation(Launcher launcher) { return new ScaleAndTranslation(0.9f, 0f, 0f); } Override public int getVisibleElements(Launcher launcher) { return HOTSEAT | WIDGETS; // 只显示热区和部件 } Override public void onStateEnabled(Launcher launcher) { super.onStateEnabled(launcher); // 应用图标变灰效果 launcher.getWorkspace().setChildrenAlpha(0.5f); } Override public void onStateDisabled(Launcher launcher) { super.onStateDisabled(launcher); // 恢复图标颜色 launcher.getWorkspace().setChildrenAlpha(1f); } Override public int getTransitionDuration(Launcher launcher, boolean isToState) { return isToState ? 300 : 200; } }关键实现要点状态标志位通过位掩码组合定义状态特性FLAG_DISABLE_ACCESSIBILITY禁用无障碍服务FLAG_DISABLE_RESTORE禁止状态自动恢复FLAG_WORKSPACE_HAS_SYSTEM_UI_SCRIM显示系统UI遮罩视觉变换工作区缩放至90%仅保留热区和部件可见图标透明度设为50%状态过渡进入状态动画时长300ms退出状态动画时长200ms3. 在 StateManager 中注册新状态修改src/com/android/launcher3/LauncherState.java添加状态定义// 在状态序数常量区添加 private static final int FOCUS_STATE_ORDINAL 12; // 在状态声明区添加 public static final LauncherState FOCUS new FocusState(FOCUS_STATE_ORDINAL);更新StateManager的状态切换逻辑添加双击桌面触发条件public class Launcher extends BaseDraggingActivity { private void setupStateHandlers() { getWorkspace().setOnTouchListener(new View.OnTouchListener() { private GestureDetector gestureDetector new GestureDetector( Launcher.this, new GestureDetector.SimpleOnGestureListener() { Override public boolean onDoubleTap(MotionEvent e) { if (mStateManager.getState() NORMAL) { mStateManager.goToState(FOCUS); } else if (mStateManager.getState() FOCUS) { mStateManager.goToState(NORMAL); } return true; } }); Override public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } }); } }注意实际实现中应考虑添加防误触机制建议设置300ms的双击间隔阈值4. 实现状态过渡动画效果创建自定义过渡动画需要修改src/com/android/launcher3/anim/AnimatorSetBuilder.java添加专注状态特有的插值器public void buildAnimation(StateManager stateManager, LauncherState fromState, LauncherState toState) { if (fromState NORMAL toState FOCUS) { // 进入专注模式的动画 addAnimation(mWorkspace, ObjectAnimator.ofFloat(mWorkspace, scaleX, 1f, 0.9f), new DecelerateInterpolator()); addAnimation(mWorkspace, ObjectAnimator.ofFloat(mWorkspace, alpha, 1f, 0.5f), new AccelerateDecelerateInterpolator()); } else if (fromState FOCUS toState NORMAL) { // 退出专注模式的动画 addAnimation(mWorkspace, ObjectAnimator.ofFloat(mWorkspace, scaleX, 0.9f, 1f), new OvershootInterpolator(1.2f)); addAnimation(mWorkspace, ObjectAnimator.ofFloat(mWorkspace, alpha, 0.5f, 1f), new LinearInterpolator()); } }推荐使用的动画插值器组合进入专注模式缩放减速插值器Decelerate透明度加速减速插值器退出专注模式缩放过冲插值器Overshoot透明度线性插值器5. 高级定制状态持久化与条件触发为了让专注模式更加实用我们需要实现以下增强功能1. 状态持久化存储修改FocusState类添加SharedPreferences支持Override public void onStateEnabled(Launcher launcher) { super.onStateEnabled(launcher); PreferenceManager.getDefaultSharedPreferences(launcher) .edit() .putBoolean(pref_focus_mode, true) .apply(); } Override public void onStateDisabled(Launcher launcher) { super.onStateDisabled(launcher); PreferenceManager.getDefaultSharedPreferences(launcher) .edit() .putBoolean(pref_focus_mode, false) .apply(); }2. 定时自动退出添加倒计时功能30分钟后自动恢复正常状态private Handler mHandler new Handler(); private Runnable mExitFocusRunnable () - { mStateManager.goToState(NORMAL); }; Override public void onStateEnabled(Launcher launcher) { // ...原有代码... mHandler.postDelayed(mExitFocusRunnable, 30 * 60 * 1000); } Override public void onStateDisabled(Launcher launcher) { // ...原有代码... mHandler.removeCallbacks(mExitFocusRunnable); }3. 多条件触发机制扩展触发方式支持以下场景自动进入专注模式连接特定Wi-Fi网络时进入特定地理位置时系统进入省电模式时实现代码示例public class FocusModeReceiver extends BroadcastReceiver { Override public void onReceive(Context context, Intent intent) { Launcher launcher Launcher.getLauncher(context); String action intent.getAction(); if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { NetworkInfo info intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); if (info ! null info.isConnected()) { WifiManager wifi (WifiManager)context.getSystemService(Context.WIFI_SERVICE); if (office_wifi.equals(wifi.getConnectionInfo().getSSID())) { launcher.getStateManager().goToState(FOCUS); } } } } }6. 调试与性能优化技巧在实现自定义状态时以下几个调试技巧能帮你节省大量时间1. 状态切换日志在StateManager中添加调试日志public void goToState(LauncherState state) { Log.d(StateManager, Transition from getState() to state); // ...原有代码... }2. 性能监测使用adb shell dumpsys gfxinfo检查动画性能adb shell dumpsys gfxinfo com.android.launcher3重点关注以下指标指标正常范围说明Draw2ms绘制时间Prepare1ms准备时间Process4ms处理时间Execute6ms执行时间3. 内存占用分析使用 Android Studio 的 Memory Profiler 检查状态切换时的内存变化特别注意位图资源是否及时释放动画对象是否被正确回收监听器是否被适当注销4. 常见问题排查清单遇到状态切换异常时按以下步骤检查确认状态已在LauncherState.java中正确定义检查状态序数ordinal是否唯一验证状态标志位组合是否合理确保过渡动画时长设置恰当排查是否有其他模块覆盖了触摸事件7. 扩展思路与其他系统功能联动专注模式的真正价值在于与其他系统功能的深度整合以下是几个值得尝试的方向1. 与勿扰模式集成AudioManager audio (AudioManager)getSystemService(AUDIO_SERVICE); NotificationManager notify (NotificationManager)getSystemService(NOTIFICATION_SERVICE); Override public void onStateEnabled(Launcher launcher) { // ...原有代码... audio.setRingerMode(AudioManager.RINGER_MODE_SILENT); notify.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE); }2. 工作资料支持UserManager um (UserManager)getSystemService(USER_SERVICE); if (um.isManagedProfile(UserHandle.myUserId())) { // 在工作资料中启用更严格的控制 getWorkspace().setChildrenAlpha(0.3f); setFlag(FLAG_DISABLE_WIDGETS, true); }3. 动态壁纸响应WallpaperManager wm WallpaperManager.getInstance(this); wm.setWallpaperOffsetSteps(0.5f, 0.5f); wm.setWallpaperOffsets(getWindow().getDecorView() .getRootView().getWindowToken(), 0.5f, 0.5f);在实现这些高级功能时务必注意处理好生命周期事件和权限申请特别是在 Android 14 更严格的后台限制下需要合理使用前台服务或WorkManager来保证功能可靠性。