斯蒂芬大强库里 發表於 2025-10-24 16:47:00

Launcher 桌面源码笔记一

<p>3D车模通过TaskView显示在Launcher,首先需要知道,为什么要用TaskView,而不是Activity,然后在说加载流程</p>
<p>1、surface比activity等效率更高,特别是针对车模跟地图等重量级场景</p>
<p>2、切换桌面等场景时,可以更精确的控制暂停恢复</p>
<p>3、进程隔离,更精细的生命周期管理跟控制</p>
<p>4、taskView中SurfaceControl的跨进程绑定机制(reparent操作)效率比binder通讯效率更高</p>
<h4>android.app.ActivityView(标记为弃用‌)</h4>
<p>跟TaskView一样都是Android系统中用于管理多窗口和任务嵌入的组件</p>
<div>
<div class="cnblogs_code"><img id="code_img_closed_9267a331-89e9-468a-b6d2-9aa090e95246" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_9267a331-89e9-468a-b6d2-9aa090e95246" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_9267a331-89e9-468a-b6d2-9aa090e95246" 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> ActivityView <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> ViewGroup {
    </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 DISPLAY_NAME = "ActivityViewVirtualDisplay"<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)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String TAG = "ActivityView"<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><span style="color: rgba(0, 0, 0, 1)"> SurfaceView mSurfaceView;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Surface mSurface;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceCallback mSurfaceCallback;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> StateCallback mActivityViewCallback;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> IActivityManager mActivityManager;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> TaskStackListener mTaskStackListener;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ActivityView(Context context) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>(context, (AttributeSet)<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)">public</span><span style="color: rgba(0, 0, 0, 1)"> ActivityView(Context context, AttributeSet attrs) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>(context, attrs, 0<span style="color: rgba(0, 0, 0, 1)">);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> ActivityView(Context context, AttributeSet attrs, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> defStyle) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(context, attrs, defStyle);
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mActivityManager =<span style="color: rgba(0, 0, 0, 1)"> ActivityManager.getService();
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mSurfaceView = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceView(context);
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mSurfaceCallback = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceCallback();
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mSurfaceView.getHolder().addCallback(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mSurfaceCallback);
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.addView(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mSurfaceView);
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>从源码中看到,继承自ViewGroup,基于SurfaceView实现,在初始化时将&nbsp;SurfaceView addView到ViewGroup中</p>
<p><code>ActivityView</code>‌ 直接依赖传统的窗口管理机制,通过&nbsp;<code>WindowManager</code>&nbsp;控制嵌入的 Activity 生命周期。</p>
<h4>com.android.wm.shell.TaskView</h4>
<div class="cnblogs_code"><img id="code_img_closed_1c339779-47a6-40d4-ba04-355d4bd63693" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_1c339779-47a6-40d4-ba04-355d4bd63693" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_1c339779-47a6-40d4-ba04-355d4bd63693" 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> TaskView <span style="color: rgba(0, 0, 255, 1)">extends</span> SurfaceView <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceHolder.Callback, ShellTaskOrganizer.TaskListener, ViewTreeObserver.OnComputeInternalInsetsListener {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ShellTaskOrganizer mTaskOrganizer;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ActivityManager.RunningTaskInfo mTaskInfo;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> WindowContainerToken mTaskToken;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceControl mTaskLeash;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> SurfaceControl.Transaction mTransaction = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SurfaceControl.Transaction();

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> TaskView(Context context, ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span>(context, (AttributeSet)<span style="color: rgba(0, 0, 255, 1)">null</span>, 0, 0, <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)">this</span>.getHolder().addCallback(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<div class="cnblogs_code"><img id="code_img_closed_e289d41d-bc79-4c1e-8243-1fc4b5d90f82" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_e289d41d-bc79-4c1e-8243-1fc4b5d90f82" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_e289d41d-bc79-4c1e-8243-1fc4b5d90f82" 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><span style="color: rgba(0, 0, 0, 1)"> onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskInfo =<span style="color: rgba(0, 0, 0, 1)"> taskInfo;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskToken =<span style="color: rgba(0, 0, 0, 1)"> taskInfo.token;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskLeash =<span style="color: rgba(0, 0, 0, 1)"> leash;
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mSurfaceCreated) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mTransaction.reparent(<span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskLeash, <span style="color: rgba(0, 0, 255, 1)">this</span>.getSurfaceControl()).show(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mTaskLeash).apply();
      } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.updateTaskVisibility();
      }

      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskOrganizer.setInterceptBackPressedOnTaskRoot(<span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskToken, <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)">this</span><span style="color: rgba(0, 0, 0, 1)">.onLocationChanged();
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskInfo.taskDescription != <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)">int</span> backgroundColor =<span style="color: rgba(0, 0, 0, 1)"> taskInfo.taskDescription.getBackgroundColor();
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mSyncQueue.runInSync((t) -&gt; <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setResizeBackgroundColor(t, backgroundColor));
      }

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.mListener != <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)">int</span> taskId =<span style="color: rgba(0, 0, 0, 1)"> taskInfo.taskId;
            ComponentName baseActivity </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.baseActivity;
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mListenerExecutor.execute(() -&gt; <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mListener.onTaskCreated(taskId, baseActivity));
      }

    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
Android 12 引入的替代方案,专为 Android Automotive OS (AAOS) 优化,并扩展了&nbsp;<code>ShellTaskOrganizer.TaskListener</code>&nbsp;接口。
<p>直接继承自SurfaceView,并且在onTaskAppeared回调中使用了reparent操作,支持动态调整嵌入任务的位置和大小‌。</p>
<h4>车模加载流程</h4>
<p>车模属于unity交互,在android中提供一个容器用于显示,这里直接使用Activity</p>
<div class="cnblogs_code"><img id="code_img_closed_b2398794-a387-4741-8628-459ada190564" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_b2398794-a387-4741-8628-459ada190564" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_b2398794-a387-4741-8628-459ada190564" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">androidx.fragment.app.FragmentContainerView
      </span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/unity_player_fragment"</span><span style="color: rgba(255, 0, 0, 1)">
      android:name</span><span style="color: rgba(0, 0, 255, 1)">="com.test.UnityPlayerFragment"</span><span style="color: rgba(255, 0, 0, 1)">
      android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
      android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>新建一个CarLauncherActivity用于显示这个UnityPlayerFragment</p>
<p>3DActivity有了,需要将它显示到launcher桌面(MainActivity),自定义TaskView,用于3D桌面</p>
<div class="cnblogs_code"><img id="code_img_closed_243e6112-7b39-4ebd-a20a-5fb1fb073f13" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_243e6112-7b39-4ebd-a20a-5fb1fb073f13" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_243e6112-7b39-4ebd-a20a-5fb1fb073f13" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">com.test.TaskViewCompat
      </span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/launcher3d"</span><span style="color: rgba(255, 0, 0, 1)">
      android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="0dp"</span><span style="color: rgba(255, 0, 0, 1)">
      android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="0dp"</span><span style="color: rgba(255, 0, 0, 1)">
      android:visibility</span><span style="color: rgba(0, 0, 255, 1)">="invisible"</span><span style="color: rgba(255, 0, 0, 1)">
      app:layout_constraintBottom_toBottomOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span><span style="color: rgba(255, 0, 0, 1)">
      app:layout_constraintEnd_toEndOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span><span style="color: rgba(255, 0, 0, 1)">
      app:layout_constraintStart_toStartOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span><span style="color: rgba(255, 0, 0, 1)">
      app:layout_constraintTop_toTopOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>在MainActivity启动时通过&nbsp;surfaceCreated 回调,对桌面进行初始化操作</p>
<div class="cnblogs_code"><img id="code_img_closed_09a2b398-9a4c-45ce-a1f2-d2c5ed85ac91" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_09a2b398-9a4c-45ce-a1f2-d2c5ed85ac91" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_09a2b398-9a4c-45ce-a1f2-d2c5ed85ac91" 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><span style="color: rgba(0, 0, 0, 1)"> surfaceCreated(SurfaceHolder holder) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mSurfaceCreated = <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)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.mListener != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mIsInitialized) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mIsInitialized = <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)">this</span>.mListenerExecutor.execute(() -&gt; <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mListener.onInitialized());
      }

      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.mShellExecutor.execute(() -&gt;<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, 255, 1)">this</span>.mTaskToken != <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)">this</span>.mTransaction.reparent(<span style="color: rgba(0, 0, 255, 1)">this</span>.mTaskLeash, <span style="color: rgba(0, 0, 255, 1)">this</span>.getSurfaceControl()).show(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mTaskLeash).apply();
                </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.updateTaskVisibility();
            }
      });
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>接下来需要实现嵌入操作,可以看到在首次进入时,会调用&nbsp;TaskView. Listener的&nbsp;onInitialized 方法,在回调中需要执行taskview的startActivity进行内嵌</p>
<div class="cnblogs_code"><img id="code_img_closed_d6e5ba11-8421-4f6e-9ac7-77e3a746e17d" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_d6e5ba11-8421-4f6e-9ac7-77e3a746e17d" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_d6e5ba11-8421-4f6e-9ac7-77e3a746e17d" 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><span style="color: rgba(0, 0, 0, 1)"> startActivity(PendingIntent pendingIntent, Intent fillInIntent, ActivityOptions options, Rect launchBounds) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.prepareActivityOptions(options, launchBounds);

      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            pendingIntent.send(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mContext, 0, fillInIntent, (PendingIntent.OnFinished)<span style="color: rgba(0, 0, 255, 1)">null</span>, (Handler)<span style="color: rgba(0, 0, 255, 1)">null</span>, (String)<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">, options.toBundle());
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
            </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException(e);
      }
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>startActivity后会触发状态变更,系统层处理后,在Systemui层通过TaskOrganizer监听状态</p>
<div>
<h4>android.window.TaskOrganizer</h4>
<p>当需要嵌入显示另一个应用的&nbsp;<code>Activity</code>&nbsp;时,<code>TaskOrganizer</code>&nbsp;会提供该任务窗口的&nbsp;<code>SurfaceControl</code>(称为 "leash"),但是TaskOrganizer位与SystemUI模块,所以需要通过AIDL进行跨进程通讯</p>
</div>
<p>首先在launcher模块定义好接口</p>
<div class="cnblogs_code"><img id="code_img_closed_37cc7316-df02-4040-a2ce-47d8afdf6a56" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_37cc7316-df02-4040-a2ce-47d8afdf6a56" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_37cc7316-df02-4040-a2ce-47d8afdf6a56" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.view.SurfaceControl;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Rect;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.window.WindowContainerToken;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell.RunningTaskInfo;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
* {@hide}
</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)">interface</span><span style="color: rgba(0, 0, 0, 1)"> ITaskView {
    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when a Task is starting and the system would like to show a UI to indicate that an
   * application is starting. The client is responsible to add/remove the starting window if it
   * has create a starting window for the Task.
   *
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> info The information about the Task that's available
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> appToken Token of the application being started.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

    <span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when the Task want to remove the starting window.
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> removalInfo The information used to remove the starting window.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

    <span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when the Task want to copy the splash screen.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span> copySplashScreenView(<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, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when the Task removed the splash screen.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span> onAppSplashScreenViewRemoved(<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, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * A callback when the Task is available for the registered organizer. The client is responsible
   * for releasing the SurfaceControl in the callback. For non-root tasks, the leash may initially
   * be hidden so it is up to the organizer to show this task.
   *
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> taskInfo The information about the Task that's available
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> leash A persistent leash for this Task.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onTaskAppeared(in RunningTaskInfo taskInfo, in SurfaceControl leash);
    </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onTaskVanished(in RunningTaskInfo taskInfo);

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Will fire when core attributes of a Task's info change. Relevant properties include the
   * {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> WindowConfiguration.ActivityType} and whether it is resizable.
   *
   * This is used, for example, during split-screen. The flow for starting is: Something sends an
   * Intent with windowingmode. Then WM finds a matching root task and launches the new task into
   * it. This causes the root task's info to change because now it has a task when it didn't
   * before. The default Divider implementation interprets this as a request to enter
   * split-screen mode and will move all other Tasks into the secondary root task. When WM
   * applies this change, it triggers an info change in the secondary root task because it now
   * has children. The Divider impl looks at the info and can see that the secondary root task
   * has adopted an ActivityType of HOME and proceeds to show the minimized dock UX.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onTaskInfoChanged(in RunningTaskInfo taskInfo);

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when the task organizer has requested
   * {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> ITaskOrganizerController.setInterceptBackPressedOnTaskRoot} to get notified when the
   * user has pressed back on the root activity of a task controlled by the task organizer.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onBackPressedOnTaskRoot(in RunningTaskInfo taskInfo);

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Called when the IME has drawn on the organized task.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">void</span> onImeDrawnOnTask(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> taskId);
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>并且提供Service</p>
<div class="cnblogs_code"><img id="code_img_closed_ecb3a70a-64ab-4eef-8c2e-593b8d9a0582" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_ecb3a70a-64ab-4eef-8c2e-593b8d9a0582" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_ecb3a70a-64ab-4eef-8c2e-593b8d9a0582" class="cnblogs_code_hide">
<pre>&lt;application android:name="com.testCarLauncherApp"&gt;
      &lt;<span style="color: rgba(0, 0, 0, 1)">service
            android:name</span>="com.test.SharedTaskViewService"<span style="color: rgba(0, 0, 0, 1)">
            android:enabled</span>="true"<span style="color: rgba(0, 0, 0, 1)">
            android:exported</span>="true" /&gt;
    &lt;/application&gt;

<span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.test.taskview;

</span><span style="color: rgba(0, 0, 255, 1)">import</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.app.Service;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.content.Intent;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.os.Handler;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.os.IBinder;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.os.Looper;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.util.Log;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.view.SurfaceControl;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell.ITaskView;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell.ShellTaskOrganizer;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell.RunningTaskInfo;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.android.wm.shell.common.HandlerExecutor;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.ConcurrentHashMap;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> SharedTaskViewService <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> Service {
    </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 = "SharedTaskViewService"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> ConcurrentHashMap&lt;Integer, Integer&gt; taskIdDisplayMap = <span style="color: rgba(0, 0, 255, 1)">new</span> ConcurrentHashMap&lt;&gt;<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> HandlerExecutor mExecutor = <span style="color: rgba(0, 0, 255, 1)">new</span> HandlerExecutor(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Handler(Looper.getMainLooper()));


    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span> getRealDisplayId(<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><span style="color: rgba(0, 0, 0, 1)"> (taskIdDisplayMap.containsKey(taskId)) {
            Integer val </span>=<span style="color: rgba(0, 0, 0, 1)"> taskIdDisplayMap.get(taskId);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (val == <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)">return</span> -1<span style="color: rgba(0, 0, 0, 1)">;
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> val.intValue();
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> -2<span style="color: rgba(0, 0, 0, 1)">;
    }

    ITaskView taskView </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ITaskView.Stub() {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> copySplashScreenView(<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)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onAppSplashScreenViewRemoved(<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)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
            mExecutor.execute(() </span>-&gt; SharedTaskViewService.<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.onTaskAppeared(taskInfo, leash));
      }

      </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)"> onTaskVanished(RunningTaskInfo taskInfo) {
            mExecutor.execute(() </span>-&gt; SharedTaskViewService.<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.onTaskVanished(taskInfo));
      }


      </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)"> onTaskInfoChanged(RunningTaskInfo taskInfo) {
            mExecutor.execute(() </span>-&gt; SharedTaskViewService.<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.onTaskInfoChanged(taskInfo));
      }


      </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)"> onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {

      }

      </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * Called when the IME has drawn on the organized task.
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
      <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onImeDrawnOnTask(<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)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (SharedTaskManager.getInstance().getListeners() != <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)">if</span> (taskInfo != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info.baseIntent != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info.baseIntent.getComponent() != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                String pkgName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getPackageName();
                String clsName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getClassName();
                Log.w(TAG, </span>"onTaskAppeared clsName:" +<span style="color: rgba(0, 0, 0, 1)"> clsName);
                </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> hasKey =<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().containsKey(clsName);
                </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> hasTaskLeash =<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().hasTaskLeash(clsName);
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasTaskLeash) {
                  SharedTaskManager.getInstance().addOrUpdateTaskLeash(clsName, </span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.SharedTaskInfo(leash, taskInfo.info.token));
                }

                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasKey) {
                  ShellTaskOrganizer.TaskListener taskListener </span>=<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().get(clsName);
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskListener != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        Logger.w(TAG, </span>"onTaskAppeared:" + pkgName + "displayId:" +<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.displayId);
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskInfo.info.displayId == 0 &amp;&amp; taskInfo.info.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW &amp;&amp; taskInfo.info.numActivities &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                            taskIdDisplayMap.put(taskInfo.info.taskId, </span>0<span style="color: rgba(0, 0, 0, 1)">);
                            taskListener.onTaskAppeared(taskInfo.info, leash);
                        }
                  }
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                  Log.w(TAG, </span>"onTaskAppeared,no suiteable key in TaskManager.getInstance().getListeners:" +<span style="color: rgba(0, 0, 0, 1)"> pkgName);
                }

            }
      }
    }

    </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)"> onTaskVanished(RunningTaskInfo taskInfo) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (SharedTaskManager.getInstance().getListeners() != <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)">if</span> (taskInfo != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info.realActivity != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                String pkgName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getPackageName();
                String clsName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getClassName();
                </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> hasKey =<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().containsKey(clsName);
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasKey) {
                  ShellTaskOrganizer.TaskListener taskListener </span>=<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().get(clsName);
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskListener != <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)">int</span> realDisplayId =<span style="color: rgba(0, 0, 0, 1)"> getRealDisplayId(taskInfo.info.taskId);
                        Logger.w(TAG, </span>"onTaskVanished:" + pkgName + ",displayId:" + taskInfo.info.displayId + ",realDisplayId:" +<span style="color: rgba(0, 0, 0, 1)"> realDisplayId);
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (realDisplayId == 0<span style="color: rgba(0, 0, 0, 1)">) {
                            taskListener.onTaskVanished(taskInfo.info);
                        }
                  }
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                  Log.w(TAG, </span>"onTaskVanished,no suiteable key in TaskManager.getInstance().getListeners:" +<span style="color: rgba(0, 0, 0, 1)"> clsName);
                }
            }
      }
    }


    </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)"> onTaskInfoChanged(RunningTaskInfo taskInfo) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (SharedTaskManager.getInstance().getListeners() != <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)">if</span> (taskInfo != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; taskInfo.info.realActivity != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                String pkgName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getPackageName();
                String clsName </span>=<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info.baseIntent.getComponent().getClassName();
                </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> hasKey =<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().containsKey(clsName);
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasKey) {
                  ShellTaskOrganizer.TaskListener taskListener </span>=<span style="color: rgba(0, 0, 0, 1)"> SharedTaskManager.getInstance().getListeners().get(clsName);
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (taskListener != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        Logger.w(TAG, </span>"onTaskInfoChanged:" +<span style="color: rgba(0, 0, 0, 1)"> taskInfo.info);
                        taskListener.onTaskInfoChanged(taskInfo.info);
                  }
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                  Log.w(TAG, </span>"onTaskInfoChanged,no suiteable key in TaskManager.getInstance().getListeners:" +<span style="color: rgba(0, 0, 0, 1)"> clsName);
                }
            }
      }
    }


    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> IBinder onBind(Intent intent) {
      Logger.w(TAG, </span>"onBind: "<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (IBinder) taskaskView;
    }

    @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)"> onCreate() {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate();
      Logger.w(TAG, </span>"onCreate: "<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)"> onDestroy() {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onDestroy();
      Logger.w(TAG, </span>"onDestroy: "<span style="color: rgba(0, 0, 0, 1)">);
    }
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
<p>SystemUI模块需要继承TaskOrganizer,在TaskOrganizer的onTaskAppeared中去同步到Launcher模块</p>
<div class="cnblogs_code"><img id="code_img_closed_c14b3f29-bba9-4209-826d-f569aabca193" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_c14b3f29-bba9-4209-826d-f569aabca193" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_c14b3f29-bba9-4209-826d-f569aabca193" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> bind(){
      Intent intent </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Intent();
      intent.setComponent(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ComponentName(PACKAGE_LAUNCHER, SERVICE_LAUNCHER_TASK_VIEW));
      mContext.bindService(intent,connection,Context.BIND_AUTO_CREATE);
      Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, </span>"bind SharedTaskViewService"<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> ServiceConnection connection = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ServiceConnection() {
      @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)"> onServiceConnected(ComponentName name, IBinder service) {
            </span><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (mLock) {
                StringBuilder tempInfoString </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuilder();
                </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (TaskAppearedInfo taskAppearedInfo : tempInfoList) {
                  tempInfoString.append(getPackageName(taskAppearedInfo.getTaskInfo())).append(</span>","<span style="color: rgba(0, 0, 0, 1)">);
                }
                Log.d(TAG, </span>"onServiceConnected name = " + name + ", tempInfoList = " +<span style="color: rgba(0, 0, 0, 1)"> tempInfoString);
                ProtoLog.v(WM_SHELL_TASK_ORG, </span>"onServiceConnected name = " +<span style="color: rgba(0, 0, 0, 1)"> name);
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                iTaskView </span>=<span style="color: rgba(0, 0, 0, 1)"> ITaskView.Stub.asInterface(service);
                isConnecting </span>= <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)">if</span>(tempInfoList.size()&gt;0<span style="color: rgba(0, 0, 0, 1)">){
                  </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                        Log.d(TAG, </span>"tempInfo is not null, notify launcher"<span style="color: rgba(0, 0, 0, 1)">);
                        </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (TaskAppearedInfo taskAppearedInfo : tempInfoList) {
                            Log.d(TAG, </span>"tempInfo = " +<span style="color: rgba(0, 0, 0, 1)"> getPackageName(taskAppearedInfo.getTaskInfo()));
                            RunningTaskInfo runningTaskInfo </span>=<span style="color: rgba(0, 0, 0, 1)"> taskAppearedInfo.getTaskInfo();
                            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (runningTaskInfo == <span style="color: rgba(0, 0, 255, 1)">null</span> || runningTaskInfo.numActivities == 0<span style="color: rgba(0, 0, 0, 1)">) {
                              Log.d(TAG, </span>"ignore empty taskInfo " +<span style="color: rgba(0, 0, 0, 1)"> runningTaskInfo);
                            } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                              iTaskView.onTaskAppeared(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RunningTaskInfo(taskAppearedInfo.getTaskInfo()), taskAppearedInfo.getLeash());
                            }
                        }
                        tempInfoList.clear();
                  } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (RemoteException e) {
                        e.printStackTrace();
                  }
                }
            }
      }

      @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)"> onServiceDisconnected(ComponentName name) {
            Log.d(TAG,</span>"onServiceDisconnected componentName="+<span style="color: rgba(0, 0, 0, 1)">name);
            iTaskView </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            bind();
      }

      @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)"> onBindingDied(ComponentName name) {
            Log.d(TAG,</span>"onBindingDied componentName="+<span style="color: rgba(0, 0, 0, 1)">name);
            iTaskView </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            bind();
      }
    };

@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)"> onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
      Log.d(TAG, </span>"task appeared " +<span style="color: rgba(0, 0, 0, 1)"> getPackageName(taskInfo));
      </span><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (mLock) {
            iTaskView.onTaskAppeared(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RunningTaskInfo(info.getTaskInfo()), info.getLeash());
      }
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>初始化时通过bind()方法绑定服务,在onTaskAppeared回调中调用服务方法</p>
<p>Launcher在收到AIDL方法onTaskAppeared时会执行&nbsp;mTransaction.reparent(mTaskLeash, getSurfaceControl()) 显示当前车模桌面</p>
<p>&nbsp;</p>
</div>
<div><span style="color: rgba(51, 51, 51, 1); font-family: &quot;PingFang SC&quot;, Arial, sans-serif; font-size: 16px">&nbsp;</span></div><br><br>
来源:https://www.cnblogs.com/LiuZhen/p/19163769
頁: [1]
查看完整版本: Launcher 桌面源码笔记一