惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
罗磊的独立博客
雷峰网
雷峰网
量子位
V
Visual Studio Blog
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
宝玉的分享
宝玉的分享
月光博客
月光博客
Martin Fowler
Martin Fowler
aimingoo的专栏
aimingoo的专栏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
腾讯CDC
Engineering at Meta
Engineering at Meta
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
Jina AI
Jina AI
A
About on SuperTechFans

博客园 - 翻滚的咸鱼

Ops权限行为记录源码解析 TaskView方案框架原理 视频解码器问题 常用命令 扫光动效 引导记录 性能优化 View共享动效 常用脚本文件 Launcher 卡片框架多模块集成 Launcher 桌面源码笔记一 氛围灯动态屏保取色方案二 氛围灯动态屏保取色方案一 自定义最近任务管理器 anr问题 TV RecyclerView 焦点处理笔记 多类型适配器 多屏下字体自动取色 阻尼拉伸方案 图片区域点击处理 RecyclerView设置默认焦点跟多页面焦点抢占 TV RecyclerView 滑动后操作保持落焦在左侧第一个View Fragment翻盖动效 当个View下,使用Drawable入场退场动画
Launcher 桌面源码笔记二
翻滚的咸鱼 · 2025-10-27 · via 博客园 - 翻滚的咸鱼

车模桌面加载成功后,需要各种交互

切换桌面处理

先补充如何切换桌面,初始化需要指定一个默认桌面,初始化其实两个桌面都会一起加载,假设默认是车模桌面,地图将不会初始化操作,但是地图桌面会内嵌到Launcher中

两个桌面是互斥的,基于这种模式下,就需要隐藏另一个桌面,因为切换动效的缘故,这里直接使用setTranslationX移出屏幕外处理

为了让两个桌面互斥,需要通过 mActivityManager.moveTaskToFront(getTaskId(), 0) 方法让两个taskview内嵌的activity只能一个处于前台,另一个pause

public void maybeBringEmbeddedTaskToForeground(int taskId) {
        if (taskId > 0) {
            // The task in TaskView should be in top to make it visible.
            // NOTE: Tried setTaskAlwaysOnTop before, the flag has some side effect to hinder
            // AccessibilityService from finding the correct window geometry: b/197247311
            mActivityManager.moveTaskToFront(taskId, /* flags= */ 0);
        }
    }

View Code

同时将两个taskview内嵌后,又单独处理了各自的生命周期,达到互斥效果

3D桌面跟Launcher通讯

这里3D桌面需要额外处理,因为3D有个通讯进程,需要监听底层信号对车模进行同步操作,而由于unity无法监听到底层信号,所以需要跟launcher进行跨进程通讯

所以在3D处于pause时,需要将通讯进程也暂停,否则信号会一直发送,并且3D也无法接受信号

override fun setUnityVisible(visible: Boolean) {
            Log.w(TAG, "setUnityVisible:${visible}")
            val fragment = UnityPlayerFragment.Current
                if (fragment != null && fragment.isLoadUnityFinish) {
                    lastVisibleFromLauncher3 = visible
                    Log.w(TAG, "setUnityVisible:setInteractionMsg $visible")
                    if (visible) {
                        fragment.resumeUnityPlayer()
                    } else {
                        fragment.pauseUnityPlayer()
                    }
                }
        }

    }

View Code

跨进程通讯接口

package com.carlauncher;
import android.os.Bundle;
import com.carlauncher.IUnityBridgeCallback;

interface UnityInterface {


    oneway void registerUnityBridgeCallback(IUnityBridgeCallback callback);
    oneway void unregisterUnityBridgeCallback(IUnityBridgeCallback callback);

    /**
     * 通知Unity 交互信息传递
     * 交互信息传输专用,除Adapter都放这里  EX:车衣按钮被点击 | 天气信息传递(bx1e) | 其他
     *
     * @param msgType 消息类型
     * @param msgData 消息
     */
    oneway void setInteractionMsg(int msgType, in Bundle bundle);


   /**
    * 设置Unity是否处于显示状态
    */
    oneway void setUnityVisible(boolean visible);

}

View Code

在service中实现接口,通过setInteractionMsg方法跟unity车模交互通讯

通讯队列

信号不断的上报,需要缓存信号然后实时发送同步到3D,这里需要在子线程中不断轮询

public class AutoPullExecutor<K, E> extends Thread {
    private static final String TAG = "AutoPullExecutor";
    private final FilterCache<K, E> mCache;
    private final List<FilterCacheHelper.OnPullCacheCallback<K, E>> mCallbacks;
    private boolean mIsRunning = false;

    public AutoPullExecutor(FilterCache<K, E> cache) {
        mCache = cache;
        mCallbacks = new ArrayList<>();
    }

    @Override
    public void run() {
        Log.d(TAG, "AutoPullExecutor is start");
        mIsRunning = true;
        while (mIsRunning) {
            FilterCache.Node<K, E> node = mCache.poll();

            if (node == null) {
                continue;
            }


            autoPullCallback(node);
        }
    }

    private void autoPullCallback(FilterCache.Node<K, E> node) {
        for (FilterCacheHelper.OnPullCacheCallback<K, E> callback : mCallbacks) {
            callback.onCache(node.key, node.element);
        }
    }

    void addPullCallback(FilterCacheHelper.OnPullCacheCallback<K, E> callback) {
        mCallbacks.add(callback);
    }

    boolean isRunning() {
        return mIsRunning;
    }

    void exit() {
        mIsRunning = false;
        interrupt();
        clear();
    }

    void clear() {
        mCallbacks.clear();
    }
}

View Code

注册好监听,需要发送信号时添加到缓存队列,轮询判断是否有需要发送的消息,发送完之后移除缓存