• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.quickstep;
17 
18 import static android.content.Intent.ACTION_CHOOSER;
19 import static android.view.MotionEvent.ACTION_CANCEL;
20 import static android.view.MotionEvent.ACTION_DOWN;
21 import static android.view.MotionEvent.ACTION_UP;
22 
23 import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
24 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
25 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
26 import static com.android.quickstep.GestureState.DEFAULT_STATE;
27 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
28 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
29 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
30 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
31 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
32 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
33 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
34 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
36 
37 import android.annotation.TargetApi;
38 import android.app.ActivityManager;
39 import android.app.PendingIntent;
40 import android.app.RemoteAction;
41 import android.app.Service;
42 import android.content.ComponentName;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.SharedPreferences;
46 import android.content.res.Configuration;
47 import android.graphics.Point;
48 import android.graphics.Rect;
49 import android.graphics.Region;
50 import android.graphics.drawable.Icon;
51 import android.hardware.display.DisplayManager;
52 import android.os.Build;
53 import android.os.Bundle;
54 import android.os.IBinder;
55 import android.os.Looper;
56 import android.os.SystemClock;
57 import android.os.SystemProperties;
58 import android.util.Log;
59 import android.view.Choreographer;
60 import android.view.Display;
61 import android.view.InputEvent;
62 import android.view.MotionEvent;
63 import android.view.Surface;
64 import android.view.accessibility.AccessibilityManager;
65 
66 import androidx.annotation.BinderThread;
67 import androidx.annotation.NonNull;
68 import androidx.annotation.Nullable;
69 import androidx.annotation.UiThread;
70 import androidx.annotation.WorkerThread;
71 
72 import com.android.launcher3.BaseDraggingActivity;
73 import com.android.launcher3.R;
74 import com.android.launcher3.ResourceUtils;
75 import com.android.launcher3.Utilities;
76 import com.android.launcher3.config.FeatureFlags;
77 import com.android.launcher3.provider.RestoreDbTask;
78 import com.android.launcher3.statemanager.StatefulActivity;
79 import com.android.launcher3.taskbar.TaskbarManager;
80 import com.android.launcher3.testing.TestLogging;
81 import com.android.launcher3.testing.TestProtocol;
82 import com.android.launcher3.tracing.LauncherTraceProto;
83 import com.android.launcher3.tracing.TouchInteractionServiceProto;
84 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
85 import com.android.launcher3.util.OnboardingPrefs;
86 import com.android.launcher3.util.TraceHelper;
87 import com.android.launcher3.util.WindowBounds;
88 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
89 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
90 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
91 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
92 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
93 import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
94 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
95 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
96 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
97 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
98 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
99 import com.android.quickstep.util.ActiveGestureLog;
100 import com.android.quickstep.util.AssistantUtilities;
101 import com.android.quickstep.util.ProtoTracer;
102 import com.android.quickstep.util.SplitScreenBounds;
103 import com.android.systemui.plugins.OverscrollPlugin;
104 import com.android.systemui.plugins.PluginListener;
105 import com.android.systemui.shared.recents.IOverviewProxy;
106 import com.android.systemui.shared.recents.ISystemUiProxy;
107 import com.android.systemui.shared.system.ActivityManagerWrapper;
108 import com.android.systemui.shared.system.InputChannelCompat;
109 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
110 import com.android.systemui.shared.system.InputConsumerController;
111 import com.android.systemui.shared.system.InputMonitorCompat;
112 import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController;
113 import com.android.systemui.shared.tracing.ProtoTraceable;
114 import com.android.wm.shell.onehanded.IOneHanded;
115 import com.android.wm.shell.pip.IPip;
116 import com.android.wm.shell.splitscreen.ISplitScreen;
117 import com.android.wm.shell.startingsurface.IStartingWindow;
118 import com.android.wm.shell.transition.IShellTransitions;
119 
120 import java.io.FileDescriptor;
121 import java.io.PrintWriter;
122 import java.util.Arrays;
123 import java.util.LinkedList;
124 
125 /**
126  * Service connected by system-UI for handling touch interaction.
127  */
128 @TargetApi(Build.VERSION_CODES.R)
129 public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
130         ProtoTraceable<LauncherTraceProto.Builder> {
131 
132     private static final String TAG = "TouchInteractionService";
133 
134     private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount";
135     private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE";
136     private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
137     private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
138 
139     /**
140      * System Action ID to show all apps.
141      * TODO: Use AccessibilityService's corresponding global action constant in S
142      */
143     private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
144 
145     public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
146             SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
147 
148     private int mBackGestureNotificationCounter = -1;
149     @Nullable
150     private OverscrollPlugin mOverscrollPlugin;
151 
152     /**
153      * Local IOverviewProxy implementation with some methods for local components
154      */
155     public class TISBinder extends IOverviewProxy.Stub {
156 
157         @BinderThread
onInitialize(Bundle bundle)158         public void onInitialize(Bundle bundle) {
159             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
160                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
161             IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP));
162             ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
163                     KEY_EXTRA_SHELL_SPLIT_SCREEN));
164             IOneHanded onehanded = IOneHanded.Stub.asInterface(
165                     bundle.getBinder(KEY_EXTRA_SHELL_ONE_HANDED));
166             IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface(
167                     bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS));
168             IStartingWindow startingWindow = IStartingWindow.Stub.asInterface(
169                     bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW));
170             ISmartspaceTransitionController smartspaceTransitionController =
171                     ISmartspaceTransitionController.Stub.asInterface(
172                             bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER));
173             MAIN_EXECUTOR.execute(() -> {
174                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
175                         splitscreen, onehanded, shellTransitions, startingWindow,
176                         smartspaceTransitionController);
177                 TouchInteractionService.this.initInputMonitor();
178                 preloadOverview(true /* fromInit */);
179                 mDeviceState.runOnUserUnlocked(() -> {
180                     final BaseActivityInterface ai =
181                             mOverviewComponentObserver.getActivityInterface();
182                     if (ai == null) return;
183                     ai.onOverviewServiceBound();
184                 });
185             });
186             sIsInitialized = true;
187         }
188 
189         @BinderThread
onOverviewToggle()190         public void onOverviewToggle() {
191             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
192             // If currently screen pinning, do not enter overview
193             if (mDeviceState.isScreenPinningActive()) {
194                 return;
195             }
196             TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
197             mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
198         }
199 
200         @BinderThread
201         @Override
onOverviewShown(boolean triggeredFromAltTab)202         public void onOverviewShown(boolean triggeredFromAltTab) {
203             if (triggeredFromAltTab) {
204                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
205                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW_NEXT_FOCUS);
206             } else {
207                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
208             }
209         }
210 
211         @BinderThread
212         @Override
onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)213         public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
214             if (triggeredFromAltTab && !triggeredFromHomeKey) {
215                 // onOverviewShownFromAltTab hides the overview and ends at the target app
216                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE);
217             }
218         }
219 
220         @BinderThread
221         @Override
onTip(int actionType, int viewType)222         public void onTip(int actionType, int viewType) {
223             // Please delete this method from the interface
224         }
225 
226         @BinderThread
227         @Override
onAssistantAvailable(boolean available)228         public void onAssistantAvailable(boolean available) {
229             MAIN_EXECUTOR.execute(() -> {
230                 mDeviceState.setAssistantAvailable(available);
231                 TouchInteractionService.this.onAssistantVisibilityChanged();
232             });
233         }
234 
235         @BinderThread
236         @Override
onAssistantVisibilityChanged(float visibility)237         public void onAssistantVisibilityChanged(float visibility) {
238             MAIN_EXECUTOR.execute(() -> {
239                 mDeviceState.setAssistantVisibility(visibility);
240                 TouchInteractionService.this.onAssistantVisibilityChanged();
241             });
242         }
243 
244         @BinderThread
onBackAction(boolean completed, int downX, int downY, boolean isButton, boolean gestureSwipeLeft)245         public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
246                 boolean gestureSwipeLeft) {
247             // Remove this method from the interface
248         }
249 
250         @BinderThread
onSystemUiStateChanged(int stateFlags)251         public void onSystemUiStateChanged(int stateFlags) {
252             MAIN_EXECUTOR.execute(() -> {
253                 int lastFlags = mDeviceState.getSystemUiStateFlags();
254                 mDeviceState.setSystemUiFlags(stateFlags);
255                 TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags);
256             });
257         }
258 
259         @BinderThread
onActiveNavBarRegionChanges(Region region)260         public void onActiveNavBarRegionChanges(Region region) {
261             MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
262         }
263 
264         @Override
onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets)265         public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets)  {
266             WindowBounds wb = new WindowBounds(bounds, insets);
267             MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
268         }
269 
270         @Override
onImeWindowStatusChanged(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)271         public void onImeWindowStatusChanged(int displayId, IBinder token, int vis,
272                 int backDisposition, boolean showImeSwitcher) {
273             MAIN_EXECUTOR.execute(() -> mTaskbarManager.updateImeStatus(
274                     displayId, vis, backDisposition, showImeSwitcher));
275         }
276 
getTaskbarManager()277         public TaskbarManager getTaskbarManager() {
278             return mTaskbarManager;
279         }
280 
getOverviewCommandHelper()281         public OverviewCommandHelper getOverviewCommandHelper() {
282             return mOverviewCommandHelper;
283         }
284     }
285 
286     private static boolean sConnected = false;
287     private static boolean sIsInitialized = false;
288     private RotationTouchHelper mRotationTouchHelper;
289 
isConnected()290     public static boolean isConnected() {
291         return sConnected;
292     }
293 
294 
isInitialized()295     public static boolean isInitialized() {
296         return sIsInitialized;
297     }
298 
299     private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
300             this::createLauncherSwipeHandler;
301     private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
302             this::createFallbackSwipeHandler;
303 
304     private ActivityManagerWrapper mAM;
305     private OverviewCommandHelper mOverviewCommandHelper;
306     private OverviewComponentObserver mOverviewComponentObserver;
307     private InputConsumerController mInputConsumer;
308     private RecentsAnimationDeviceState mDeviceState;
309     private TaskAnimationManager mTaskAnimationManager;
310 
311     private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
312     private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP;
313     private Choreographer mMainChoreographer;
314     private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer;
315     private GestureState mGestureState = DEFAULT_STATE;
316 
317     private InputMonitorCompat mInputMonitorCompat;
318     private InputEventReceiver mInputEventReceiver;
319 
320     private DisplayManager mDisplayManager;
321 
322     private TaskbarManager mTaskbarManager;
323 
324     @Override
onCreate()325     public void onCreate() {
326         super.onCreate();
327         // Initialize anything here that is needed in direct boot mode.
328         // Everything else should be initialized in onUserUnlocked() below.
329         mMainChoreographer = Choreographer.getInstance();
330         mAM = ActivityManagerWrapper.getInstance();
331         mDeviceState = new RecentsAnimationDeviceState(this, true);
332         mDisplayManager = getSystemService(DisplayManager.class);
333         mTaskbarManager = new TaskbarManager(this);
334 
335         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
336         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
337         mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
338         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
339         mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
340         ProtoTracer.INSTANCE.get(this).add(this);
341         sConnected = true;
342     }
343 
disposeEventHandlers()344     private void disposeEventHandlers() {
345         if (mInputEventReceiver != null) {
346             mInputEventReceiver.dispose();
347             mInputEventReceiver = null;
348         }
349         if (mInputMonitorCompat != null) {
350             mInputMonitorCompat.dispose();
351             mInputMonitorCompat = null;
352         }
353     }
354 
initInputMonitor()355     private void initInputMonitor() {
356         disposeEventHandlers();
357 
358         if (mDeviceState.isButtonNavMode()) {
359             return;
360         }
361 
362         mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
363         mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
364                 mMainChoreographer, this::onInputEvent);
365 
366         mRotationTouchHelper.updateGestureTouchRegions();
367     }
368 
369     /**
370      * Called when the navigation mode changes, guaranteed to be after the device state has updated.
371      */
onNavigationModeChanged(SysUINavigationMode.Mode mode)372     private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
373         initInputMonitor();
374         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
375     }
376 
377     /**
378      * Called when the one handed mode overlay package changes, to recreate touch region.
379      */
onOneHandedModeOverlayChanged(int newGesturalHeight)380     private void onOneHandedModeOverlayChanged(int newGesturalHeight) {
381         initInputMonitor();
382     }
383 
384     @UiThread
onUserUnlocked()385     public void onUserUnlocked() {
386         mTaskAnimationManager = new TaskAnimationManager(this);
387         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
388         mOverviewCommandHelper = new OverviewCommandHelper(this,
389                 mOverviewComponentObserver, mTaskAnimationManager);
390         mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
391         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
392         mInputConsumer.registerInputConsumer();
393         onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
394         onAssistantVisibilityChanged();
395 
396         // Temporarily disable model preload
397         // new ModelPreload().start(this);
398         mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
399                 .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT));
400         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
401 
402         PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this,
403                 OverscrollPlugin.class, false /* allowMultiple */);
404 
405         mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
406         onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame());
407     }
408 
getOverviewCommandHelper()409     public OverviewCommandHelper getOverviewCommandHelper() {
410         return mOverviewCommandHelper;
411     }
412 
resetHomeBounceSeenOnQuickstepEnabledFirstTime()413     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
414         if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
415             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
416             // mode doesn't have gestures
417             return;
418         }
419 
420         // Reset home bounce seen on quick step enabled for first time
421         SharedPreferences sharedPrefs = Utilities.getPrefs(this);
422         if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
423             sharedPrefs.edit()
424                     .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
425                     .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
426                     .apply();
427         }
428     }
429 
onOverviewTargetChange(boolean isHomeAndOverviewSame)430     private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
431         AccessibilityManager am = getSystemService(AccessibilityManager.class);
432 
433         if (isHomeAndOverviewSame) {
434             Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
435                     .setAction(Intent.ACTION_ALL_APPS);
436             RemoteAction allAppsAction = new RemoteAction(
437                     Icon.createWithResource(this, R.drawable.ic_apps),
438                     getString(R.string.all_apps_label),
439                     getString(R.string.all_apps_label),
440                     PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent,
441                             PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
442             am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
443         } else {
444             am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
445         }
446     }
447 
448     @UiThread
onSystemUiFlagsChanged(int lastSysUIFlags)449     private void onSystemUiFlagsChanged(int lastSysUIFlags) {
450         if (mDeviceState.isUserUnlocked()) {
451             int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
452             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
453             mOverviewComponentObserver.onSystemUiStateChanged();
454             mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
455 
456             if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) !=
457                     (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) {
458                 // Update the tracing state
459                 if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
460                     Log.d(TAG, "Starting tracing.");
461                     ProtoTracer.INSTANCE.get(this).start();
462                 } else {
463                     Log.d(TAG, "Stopping tracing. Dumping to file="
464                             + ProtoTracer.INSTANCE.get(this).getTraceFile());
465                     ProtoTracer.INSTANCE.get(this).stop();
466                 }
467             }
468         }
469     }
470 
471     @UiThread
onAssistantVisibilityChanged()472     private void onAssistantVisibilityChanged() {
473         if (mDeviceState.isUserUnlocked()) {
474             mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
475                     mDeviceState.getAssistantVisibility());
476         }
477     }
478 
479     @Override
onDestroy()480     public void onDestroy() {
481         Log.d(TAG, "Touch service destroyed: user=" + getUserId());
482         sIsInitialized = false;
483         if (mDeviceState.isUserUnlocked()) {
484             mInputConsumer.unregisterInputConsumer();
485             mOverviewComponentObserver.onDestroy();
486             PluginManagerWrapper.INSTANCE.get(getBaseContext()).removePluginListener(this);
487         }
488         disposeEventHandlers();
489         mDeviceState.destroy();
490         SystemUiProxy.INSTANCE.get(this).clearProxy();
491         ProtoTracer.INSTANCE.get(this).stop();
492         ProtoTracer.INSTANCE.get(this).remove(this);
493 
494         getSystemService(AccessibilityManager.class)
495                 .unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
496 
497         mTaskbarManager.destroy();
498         sConnected = false;
499         super.onDestroy();
500     }
501 
502     @Override
onBind(Intent intent)503     public IBinder onBind(Intent intent) {
504         Log.d(TAG, "Touch service connected: user=" + getUserId());
505         return new TISBinder();
506     }
507 
onInputEvent(InputEvent ev)508     private void onInputEvent(InputEvent ev) {
509         if (!(ev instanceof MotionEvent)) {
510             Log.e(TAG, "Unknown event " + ev);
511             return;
512         }
513         MotionEvent event = (MotionEvent) ev;
514         if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
515             final Display display = mDisplayManager.getDisplay(mDeviceState.getDisplayId());
516             int rotation = display.getRotation();
517             Point sz = new Point();
518             display.getRealSize(sz);
519             if (rotation != Surface.ROTATION_0) {
520                 event.transform(InputChannelCompat.createRotationMatrix(rotation, sz.x, sz.y));
521             }
522         }
523 
524         TestLogging.recordMotionEvent(
525                 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
526 
527         if (!mDeviceState.isUserUnlocked()) {
528             return;
529         }
530 
531         Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
532                 TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
533 
534         final int action = event.getAction();
535         if (action == ACTION_DOWN) {
536             mRotationTouchHelper.setOrientationTransformIfNeeded(event);
537 
538             if (!mDeviceState.isOneHandedModeActive()
539                     && mRotationTouchHelper.isInSwipeUpTouchRegion(event)) {
540                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
541                 // onConsumerInactive and wipe the previous gesture state
542                 GestureState prevGestureState = new GestureState(mGestureState);
543                 GestureState newGestureState = createGestureState(mGestureState);
544                 newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis());
545                 mConsumer.onConsumerAboutToBeSwitched();
546                 mGestureState = newGestureState;
547                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
548 
549                 ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
550                 mUncheckedConsumer = mConsumer;
551             } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
552                 mGestureState = createGestureState(mGestureState);
553                 ActivityManager.RunningTaskInfo runningTask = mGestureState.getRunningTask();
554                 if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
555                     // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
556                     // should not interrupt it. QuickSwitch assumes that interruption can only
557                     // happen if the next gesture is also quick switch.
558                     mUncheckedConsumer = new AssistantInputConsumer(
559                             this,
560                             mGestureState,
561                             InputConsumer.NO_OP, mInputMonitorCompat,
562                             mDeviceState,
563                             event);
564                 } else if (mDeviceState.canTriggerOneHandedAction(event)) {
565                     // Consume gesture event for triggering one handed feature.
566                     mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
567                         InputConsumer.NO_OP, mInputMonitorCompat);
568                 } else {
569                     mUncheckedConsumer = InputConsumer.NO_OP;
570                 }
571             } else if (mDeviceState.canTriggerOneHandedAction(event)) {
572                 // Consume gesture event for triggering one handed feature.
573                 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
574                         InputConsumer.NO_OP, mInputMonitorCompat);
575             } else {
576                 mUncheckedConsumer = InputConsumer.NO_OP;
577             }
578         } else {
579             // Other events
580             if (mUncheckedConsumer != InputConsumer.NO_OP) {
581                 // Only transform the event if we are handling it in a proper consumer
582                 mRotationTouchHelper.setOrientationTransformIfNeeded(event);
583             }
584         }
585 
586         if (mUncheckedConsumer != InputConsumer.NO_OP) {
587             switch (event.getActionMasked()) {
588                 case ACTION_DOWN:
589                 case ACTION_UP:
590                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent("
591                             + (int) event.getRawX() + ", " + (int) event.getRawY() + ")",
592                             event.getActionMasked());
593                     break;
594                 default:
595                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
596                     break;
597             }
598         }
599 
600         boolean cancelGesture = mGestureState.getActivityInterface() != null
601                 && mGestureState.getActivityInterface().shouldCancelCurrentGesture();
602         boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture)
603                 && mConsumer != null
604                 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
605         if (cancelGesture) {
606             event.setAction(ACTION_CANCEL);
607         }
608         mUncheckedConsumer.onMotionEvent(event);
609 
610         if (cleanUpConsumer) {
611             reset();
612         }
613         TraceHelper.INSTANCE.endFlagsOverride(traceToken);
614         ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
615     }
616 
createGestureState(GestureState previousGestureState)617     public GestureState createGestureState(GestureState previousGestureState) {
618         GestureState gestureState = new GestureState(mOverviewComponentObserver,
619                 ActiveGestureLog.INSTANCE.generateAndSetLogId());
620         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
621             gestureState.updateRunningTask(previousGestureState.getRunningTask());
622             gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId());
623             gestureState.updatePreviouslyAppearedTaskIds(
624                     previousGestureState.getPreviouslyAppearedTaskIds());
625         } else {
626             gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.0",
627                     () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
628         }
629         return gestureState;
630     }
631 
newConsumer(GestureState previousGestureState, GestureState newGestureState, MotionEvent event)632     private InputConsumer newConsumer(GestureState previousGestureState,
633             GestureState newGestureState, MotionEvent event) {
634         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
635 
636         if (!mDeviceState.isUserUnlocked()) {
637             if (canStartSystemGesture) {
638                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
639                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
640                 return createDeviceLockedInputConsumer(newGestureState);
641             } else {
642                 return getDefaultInputConsumer();
643             }
644         }
645 
646         // When there is an existing recents animation running, bypass systemState check as this is
647         // a followup gesture and the first gesture started in a valid system state.
648         InputConsumer base = canStartSystemGesture
649                 || previousGestureState.isRecentsAnimationRunning()
650                         ? newBaseConsumer(previousGestureState, newGestureState, event)
651                         : getDefaultInputConsumer();
652         if (mDeviceState.isGesturalNavMode()) {
653             handleOrientationSetup(base);
654         }
655         if (mDeviceState.isFullyGesturalNavMode()) {
656             if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
657                 base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat,
658                         mDeviceState, event);
659             }
660 
661             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
662                 OverscrollPlugin plugin = null;
663                 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
664                     plugin = OverscrollPluginFactory.INSTANCE.get(
665                             getApplicationContext()).getLocalOverscrollPlugin();
666                 }
667 
668                 // If not local plugin was forced, use the actual overscroll plugin if available.
669                 if (plugin == null && mOverscrollPlugin != null && mOverscrollPlugin.isActive()) {
670                     plugin = mOverscrollPlugin;
671                 }
672 
673                 if (plugin != null) {
674                     // Put the overscroll gesture as higher priority than the Assistant or base
675                     // gestures
676                     base = new OverscrollInputConsumer(this, newGestureState, base,
677                         mInputMonitorCompat, plugin);
678                 }
679             }
680 
681             // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
682             // instead of going all the way home when a swipe up is detected.
683             if (mDeviceState.isBubblesExpanded() || mDeviceState.isGlobalActionsShowing()) {
684                 base = new SysUiOverlayInputConsumer(
685                         getBaseContext(), mDeviceState, mInputMonitorCompat);
686             }
687 
688             if (mDeviceState.isScreenPinningActive()) {
689                 // Note: we only allow accessibility to wrap this, and it replaces the previous
690                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
691                 base = new ScreenPinnedInputConsumer(this, newGestureState);
692             }
693 
694             if (mDeviceState.canTriggerOneHandedAction(event)) {
695                 base = new OneHandedModeInputConsumer(this, mDeviceState, base,
696                         mInputMonitorCompat);
697             }
698 
699             if (mDeviceState.isAccessibilityMenuAvailable()) {
700                 base = new AccessibilityInputConsumer(this, mDeviceState, base,
701                         mInputMonitorCompat);
702             }
703         } else {
704             if (mDeviceState.isScreenPinningActive()) {
705                 base = getDefaultInputConsumer();
706             }
707 
708             if (mDeviceState.canTriggerOneHandedAction(event)) {
709                 base = new OneHandedModeInputConsumer(this, mDeviceState, base,
710                         mInputMonitorCompat);
711             }
712         }
713         return base;
714     }
715 
handleOrientationSetup(InputConsumer baseInputConsumer)716     private void handleOrientationSetup(InputConsumer baseInputConsumer) {
717         baseInputConsumer.notifyOrientationSetup();
718     }
719 
newBaseConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event)720     private InputConsumer newBaseConsumer(GestureState previousGestureState,
721             GestureState gestureState, MotionEvent event) {
722         if (mDeviceState.isKeyguardShowingOccluded()) {
723             // This handles apps showing over the lockscreen (e.g. camera)
724             return createDeviceLockedInputConsumer(gestureState);
725         }
726 
727         // Use overview input consumer for sharesheets on top of home.
728         boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
729                 && gestureState.getRunningTask() != null
730                 && ACTION_CHOOSER.equals(gestureState.getRunningTask().baseIntent.getAction());
731         if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
732             // In the case where we are in the excluded assistant state, ignore it and treat the
733             // running activity as the task behind the assistant
734             gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.assistant",
735                     () -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
736             ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
737             ComponentName runningComponent =
738                     gestureState.getRunningTask().baseIntent.getComponent();
739             forceOverviewInputConsumer =
740                     runningComponent != null && runningComponent.equals(homeComponent);
741         }
742 
743         if (ENABLE_QUICKSTEP_LIVE_TILE.get()
744                 && gestureState.getActivityInterface().isInLiveTileMode()) {
745             return createOverviewInputConsumer(
746                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
747         } else if (gestureState.getRunningTask() == null) {
748             return getDefaultInputConsumer();
749         } else if (previousGestureState.isRunningAnimationToLauncher()
750                 || gestureState.getActivityInterface().isResumed()
751                 || forceOverviewInputConsumer) {
752             return createOverviewInputConsumer(
753                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
754         } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
755             return getDefaultInputConsumer();
756         } else {
757             return createOtherActivityInputConsumer(gestureState, event);
758         }
759     }
760 
getSwipeUpHandlerFactory()761     public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
762         return !mOverviewComponentObserver.isHomeAndOverviewSame()
763                 ? mFallbackSwipeHandlerFactory : mLauncherSwipeHandlerFactory;
764     }
765 
createOtherActivityInputConsumer(GestureState gestureState, MotionEvent event)766     private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
767             MotionEvent event) {
768 
769         final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory();
770         final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
771                 || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
772         final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
773         return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
774                 gestureState, shouldDefer, this::onConsumerInactive,
775                 mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
776     }
777 
createDeviceLockedInputConsumer(GestureState gestureState)778     private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
779         if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
780             return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
781                     gestureState, mInputMonitorCompat);
782         } else {
783             return getDefaultInputConsumer();
784         }
785     }
786 
createOverviewInputConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event, boolean forceOverviewInputConsumer)787     public InputConsumer createOverviewInputConsumer(GestureState previousGestureState,
788             GestureState gestureState, MotionEvent event,
789             boolean forceOverviewInputConsumer) {
790         StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
791         if (activity == null) {
792             return getDefaultInputConsumer();
793         }
794 
795         if (activity.getRootView().hasWindowFocus()
796                 || previousGestureState.isRunningAnimationToLauncher()
797                 || (ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
798                     && forceOverviewInputConsumer)
799                 || (ENABLE_QUICKSTEP_LIVE_TILE.get()
800                 && gestureState.getActivityInterface().isInLiveTileMode())) {
801             return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
802                     false /* startingInActivityBounds */);
803         } else {
804             final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
805             return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
806                     mInputMonitorCompat, disableHorizontalSwipe);
807         }
808     }
809 
810     /**
811      * To be called by the consumer when it's no longer active. This can be called by any consumer
812      * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
813      * intercepting touches, the base consumer can try to call this).
814      */
onConsumerInactive(InputConsumer caller)815     private void onConsumerInactive(InputConsumer caller) {
816         if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) {
817             reset();
818         }
819     }
820 
reset()821     private void reset() {
822         mConsumer = mUncheckedConsumer = getDefaultInputConsumer();
823         mGestureState = DEFAULT_STATE;
824         // By default, use batching of the input events, but check receiver before using in the rare
825         // case that the monitor was disposed before the swipe settled
826         if (mInputEventReceiver != null) {
827             mInputEventReceiver.setBatchingEnabled(true);
828         }
829     }
830 
831     /**
832      * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP.
833      */
getDefaultInputConsumer()834     private @NonNull InputConsumer getDefaultInputConsumer() {
835         if (mResetGestureInputConsumer != null) {
836             return mResetGestureInputConsumer;
837         } else {
838             // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
839             // NO_OP until then (we never want these to be null).
840             return InputConsumer.NO_OP;
841         }
842     }
843 
preloadOverview(boolean fromInit)844     private void preloadOverview(boolean fromInit) {
845         if (!mDeviceState.isUserUnlocked()) {
846             return;
847         }
848 
849         if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
850             // Prevent the overview from being started before the real home on first boot.
851             return;
852         }
853 
854         if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) {
855             // Preloading while a restore is pending may cause launcher to start the restore
856             // too early.
857             return;
858         }
859 
860         final BaseActivityInterface activityInterface =
861                 mOverviewComponentObserver.getActivityInterface();
862         final Intent overviewIntent = new Intent(
863                 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
864         if (activityInterface.getCreatedActivity() != null && fromInit) {
865             // The activity has been created before the initialization of overview service. It is
866             // usually happens when booting or launcher is the top activity, so we should already
867             // have the latest state.
868             return;
869         }
870 
871         mTaskAnimationManager.preloadRecentsAnimation(overviewIntent);
872     }
873 
874     @Override
onConfigurationChanged(Configuration newConfig)875     public void onConfigurationChanged(Configuration newConfig) {
876         if (!mDeviceState.isUserUnlocked()) {
877             return;
878         }
879         final BaseActivityInterface activityInterface =
880                 mOverviewComponentObserver.getActivityInterface();
881         final BaseDraggingActivity activity = activityInterface.getCreatedActivity();
882         if (activity == null || activity.isStarted()) {
883             // We only care about the existing background activity.
884             return;
885         }
886         if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
887                 activity.getResources().getConfiguration().diff(newConfig))) {
888             // Since navBar gestural height are different between portrait and landscape,
889             // can handle orientation changes and refresh navigation gestural region through
890             // onOneHandedModeChanged()
891             int newGesturalHeight = ResourceUtils.getNavbarSize(
892                     ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
893                     getApplicationContext().getResources());
894             mDeviceState.onOneHandedModeChanged(newGesturalHeight);
895             return;
896         }
897 
898         preloadOverview(false /* fromInit */);
899     }
900 
901     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)902     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
903         if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
904             LinkedList<String> args = new LinkedList(Arrays.asList(rawArgs));
905             switch (args.pollFirst()) {
906                 case "cmd":
907                     if (args.peekFirst() == null) {
908                         printAvailableCommands(pw);
909                     } else {
910                         onCommand(pw, args);
911                     }
912                     break;
913             }
914         } else {
915             // Dump everything
916             FeatureFlags.dump(pw);
917             if (mDeviceState.isUserUnlocked()) {
918                 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
919             }
920             mDeviceState.dump(pw);
921             if (mOverviewComponentObserver != null) {
922                 mOverviewComponentObserver.dump(pw);
923             }
924             if (mGestureState != null) {
925                 mGestureState.dump(pw);
926             }
927             pw.println("Input state:");
928             pw.println("  mInputMonitorCompat=" + mInputMonitorCompat);
929             pw.println("  mInputEventReceiver=" + mInputEventReceiver);
930             SysUINavigationMode.INSTANCE.get(this).dump(pw);
931             pw.println("TouchState:");
932             BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
933                     : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
934             boolean resumed = mOverviewComponentObserver != null
935                     && mOverviewComponentObserver.getActivityInterface().isResumed();
936             pw.println("  createdOverviewActivity=" + createdOverviewActivity);
937             pw.println("  resumed=" + resumed);
938             pw.println("  mConsumer=" + mConsumer.getName());
939             ActiveGestureLog.INSTANCE.dump("", pw);
940             pw.println("ProtoTrace:");
941             pw.println("  file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
942         }
943     }
944 
printAvailableCommands(PrintWriter pw)945     private void printAvailableCommands(PrintWriter pw) {
946         pw.println("Available commands:");
947         pw.println("  clear-touch-log: Clears the touch interaction log");
948     }
949 
onCommand(PrintWriter pw, LinkedList<String> args)950     private void onCommand(PrintWriter pw, LinkedList<String> args) {
951         switch (args.pollFirst()) {
952             case "clear-touch-log":
953                 ActiveGestureLog.INSTANCE.clear();
954                 break;
955         }
956     }
957 
createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs)958     private AbsSwipeUpHandler createLauncherSwipeHandler(
959             GestureState gestureState, long touchTimeMs) {
960         return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
961                 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
962                 mInputConsumer);
963     }
964 
createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs)965     private AbsSwipeUpHandler createFallbackSwipeHandler(
966             GestureState gestureState, long touchTimeMs) {
967         return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
968                 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
969                 mInputConsumer);
970     }
971 
shouldNotifyBackGesture()972     protected boolean shouldNotifyBackGesture() {
973         return mBackGestureNotificationCounter > 0 &&
974                 !mDeviceState.getGestureBlockedActivityPackages().isEmpty();
975     }
976 
977     @WorkerThread
tryNotifyBackGesture()978     protected void tryNotifyBackGesture() {
979         if (shouldNotifyBackGesture()) {
980             mBackGestureNotificationCounter--;
981             Utilities.getDevicePrefs(this).edit()
982                     .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply();
983             mDeviceState.getGestureBlockedActivityPackages().forEach(blockedPackage ->
984                     sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(blockedPackage)));
985         }
986     }
987 
988     @Override
onPluginConnected(OverscrollPlugin overscrollPlugin, Context context)989     public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) {
990         mOverscrollPlugin = overscrollPlugin;
991     }
992 
993     @Override
onPluginDisconnected(OverscrollPlugin overscrollPlugin)994     public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) {
995         mOverscrollPlugin = null;
996     }
997 
998     @Override
writeToProto(LauncherTraceProto.Builder proto)999     public void writeToProto(LauncherTraceProto.Builder proto) {
1000         TouchInteractionServiceProto.Builder serviceProto =
1001             TouchInteractionServiceProto.newBuilder();
1002         serviceProto.setServiceConnected(true);
1003 
1004         if (mOverviewComponentObserver != null) {
1005             mOverviewComponentObserver.writeToProto(serviceProto);
1006         }
1007         mConsumer.writeToProto(serviceProto);
1008 
1009         proto.setTouchInteractionService(serviceProto);
1010     }
1011 }
1012