清水河 發表於 2025-10-27 13:28:00

Launcher 桌面源码笔记二

<p>车模桌面加载成功后,需要各种交互</p>
<h4>切换桌面处理</h4>
<p>先补充如何切换桌面,初始化需要指定一个默认桌面,初始化其实两个桌面都会一起加载,假设默认是车模桌面,地图将不会初始化操作,但是地图桌面会内嵌到Launcher中</p>
<p>两个桌面是互斥的,基于这种模式下,就需要隐藏另一个桌面,因为切换动效的缘故,这里直接使用setTranslationX移出屏幕外处理</p>
<p>为了让两个桌面互斥,需要通过&nbsp;mActivityManager.moveTaskToFront(getTaskId(), 0) 方法让两个taskview内嵌的activity只能一个处于前台,另一个pause</p>
<div class="cnblogs_code"><img id="code_img_closed_f257da9d-85bc-407e-9ce9-819be2b7f310" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_f257da9d-85bc-407e-9ce9-819be2b7f310" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_f257da9d-85bc-407e-9ce9-819be2b7f310" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> maybeBringEmbeddedTaskToForeground(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> taskId) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskId &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> The task in TaskView should be in top to make it visible.
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> NOTE: Tried setTaskAlwaysOnTop before, the flag has some side effect to hinder
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> AccessibilityService from finding the correct window geometry: b/197247311</span>
            mActivityManager.moveTaskToFront(taskId, <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> flags= </span><span style="color: rgba(0, 128, 0, 1)">*/</span> 0<span style="color: rgba(0, 0, 0, 1)">);
      }
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>同时将两个taskview内嵌后,又单独处理了各自的生命周期,达到互斥效果</p>
<h4>3D桌面跟Launcher通讯</h4>
<p>这里3D桌面需要额外处理,因为3D有个通讯进程,需要监听底层信号对车模进行同步操作,而由于unity无法监听到底层信号,所以需要跟launcher进行跨进程通讯</p>
<p>所以在3D处于pause时,需要将通讯进程也暂停,否则信号会一直发送,并且3D也无法接受信号</p>
<div class="cnblogs_code"><img id="code_img_closed_a6ea9216-f32a-4b8a-95c5-96b8a6453d47" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_a6ea9216-f32a-4b8a-95c5-96b8a6453d47" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_a6ea9216-f32a-4b8a-95c5-96b8a6453d47" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">override fun setUnityVisible(visible: Boolean) {
            Log.w(TAG, </span>"setUnityVisible:${visible}"<span style="color: rgba(0, 0, 0, 1)">)
            val fragment </span>=<span style="color: rgba(0, 0, 0, 1)"> UnityPlayerFragment.Current
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (fragment != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> fragment.isLoadUnityFinish) {
                  lastVisibleFromLauncher3 </span>=<span style="color: rgba(0, 0, 0, 1)"> visible
                  Log.w(TAG, </span>"setUnityVisible:setInteractionMsg $visible"<span style="color: rgba(0, 0, 0, 1)">)
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (visible) {
                        fragment.resumeUnityPlayer()
                  } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                        fragment.pauseUnityPlayer()
                  }
                }
      }

    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>跨进程通讯接口</p>
<div class="cnblogs_code"><img id="code_img_closed_e2a50d1e-baf6-421d-9396-0f7a4014981f" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_e2a50d1e-baf6-421d-9396-0f7a4014981f" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_e2a50d1e-baf6-421d-9396-0f7a4014981f" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.carlauncher;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.os.Bundle;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.carlauncher.IUnityBridgeCallback;

</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> UnityInterface {


    oneway </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> registerUnityBridgeCallback(IUnityBridgeCallback callback);
    oneway </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> unregisterUnityBridgeCallback(IUnityBridgeCallback callback);

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


   </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
    * 设置Unity是否处于显示状态
    </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    oneway </span><span style="color: rgba(0, 0, 255, 1)">void</span> setUnityVisible(<span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> visible);

}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>在service中实现接口,通过setInteractionMsg方法跟unity车模交互通讯</p>
<h5>通讯队列</h5>
<p>信号不断的上报,需要缓存信号然后实时发送同步到3D,这里需要在子线程中不断轮询</p>
<div class="cnblogs_code"><img id="code_img_closed_5c9136c5-5020-4ee0-8b8b-c8af8f02a912" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_5c9136c5-5020-4ee0-8b8b-c8af8f02a912" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_5c9136c5-5020-4ee0-8b8b-c8af8f02a912" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> AutoPullExecutor&lt;K, E&gt; <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> Thread {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String TAG = "AutoPullExecutor"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> FilterCache&lt;K, E&gt;<span style="color: rgba(0, 0, 0, 1)"> mCache;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> List&lt;FilterCacheHelper.OnPullCacheCallback&lt;K, E&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> mCallbacks;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> mIsRunning = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> AutoPullExecutor(FilterCache&lt;K, E&gt;<span style="color: rgba(0, 0, 0, 1)"> cache) {
      mCache </span>=<span style="color: rgba(0, 0, 0, 1)"> cache;
      mCallbacks </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
      Log.d(TAG, </span>"AutoPullExecutor is start"<span style="color: rgba(0, 0, 0, 1)">);
      mIsRunning </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (mIsRunning) {
            FilterCache.Node</span>&lt;K, E&gt; node =<span style="color: rgba(0, 0, 0, 1)"> mCache.poll();

            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (node == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
            }


            autoPullCallback(node);
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> autoPullCallback(FilterCache.Node&lt;K, E&gt;<span style="color: rgba(0, 0, 0, 1)"> node) {
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (FilterCacheHelper.OnPullCacheCallback&lt;K, E&gt;<span style="color: rgba(0, 0, 0, 1)"> callback : mCallbacks) {
            callback.onCache(node.key, node.element);
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">void</span> addPullCallback(FilterCacheHelper.OnPullCacheCallback&lt;K, E&gt;<span style="color: rgba(0, 0, 0, 1)"> callback) {
      mCallbacks.add(callback);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isRunning() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> mIsRunning;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> exit() {
      mIsRunning </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
      interrupt();
      clear();
    }

    </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> clear() {
      mCallbacks.clear();
    }
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>注册好监听,需要发送信号时添加到缓存队列,轮询判断是否有需要发送的消息,发送完之后移除缓存</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/LiuZhen/p/19168360
頁: [1]
查看完整版本: Launcher 桌面源码笔记二