1 /* 2 * Copyright (C) 2014 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 17 package com.android.systemui.recents; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 22 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS; 23 24 import android.app.ActivityManager; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.ServiceConnection; 29 import android.content.pm.ActivityInfo; 30 import android.content.res.Configuration; 31 import android.content.res.Resources; 32 import android.graphics.Point; 33 import android.graphics.Rect; 34 import android.hardware.display.DisplayManager; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.RemoteException; 38 import android.os.UserHandle; 39 import android.util.EventLog; 40 import android.util.Log; 41 import android.view.Display; 42 import android.widget.Toast; 43 import com.android.internal.logging.MetricsLogger; 44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 45 import com.android.systemui.EventLogConstants; 46 import com.android.systemui.EventLogTags; 47 import com.android.systemui.R; 48 import com.android.systemui.SysUiServiceProvider; 49 import com.android.systemui.pip.PipUI; 50 import com.android.systemui.recents.events.EventBus; 51 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; 52 import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; 53 import com.android.systemui.recents.events.activity.DockedTopTaskEvent; 54 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent; 55 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; 56 import com.android.systemui.recents.events.component.ExpandPipEvent; 57 import com.android.systemui.recents.events.component.HidePipMenuEvent; 58 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 59 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 60 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent; 61 import com.android.systemui.recents.events.component.ShowUserToastEvent; 62 import com.android.systemui.recents.events.ui.RecentsDrawnEvent; 63 import com.android.systemui.recents.events.ui.RecentsGrowingEvent; 64 import com.android.systemui.recents.misc.SystemServicesProxy; 65 import com.android.systemui.recents.model.RecentsTaskLoader; 66 import com.android.systemui.shared.system.ActivityManagerWrapper; 67 import com.android.systemui.stackdivider.Divider; 68 import java.io.PrintWriter; 69 import java.util.ArrayList; 70 import java.util.HashSet; 71 import java.util.Set; 72 73 /** 74 * An implementation of the SystemUI recents component, which supports both system and secondary 75 * users. 76 */ 77 public class LegacyRecentsImpl implements RecentsImplementation { 78 79 private final static String TAG = "Recents"; 80 81 public final static int EVENT_BUS_PRIORITY = 1; 82 public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000; 83 84 public final static Set<String> RECENTS_ACTIVITIES = new HashSet<>(); 85 static { 86 RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY); 87 } 88 89 private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported"; 90 private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported"; 91 private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible"; 92 93 private static SystemServicesProxy sSystemServicesProxy; 94 private static RecentsDebugFlags sDebugFlags; 95 private static RecentsTaskLoader sTaskLoader; 96 private static RecentsConfiguration sConfiguration; 97 98 private Context mContext; 99 private SysUiServiceProvider mSysUiServiceProvider; 100 private Handler mHandler; 101 private RecentsImpl mImpl; 102 103 // Only For system user, this is the callbacks instance we return to each secondary user 104 private RecentsSystemUser mSystemToUserCallbacks; 105 106 // Only for secondary users, this is the callbacks instance provided by the system user to make 107 // calls back 108 private IRecentsSystemUserCallbacks mUserToSystemCallbacks; 109 110 // The set of runnables to run after binding to the system user's service. 111 private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>(); 112 113 // Only for secondary users, this is the death handler for the binder from the system user 114 private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() { 115 @Override 116 public void binderDied() { 117 mUserToSystemCallbacks = null; 118 EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION, 119 EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND, 120 sSystemServicesProxy.getProcessUser()); 121 122 // Retry after a fixed duration 123 mHandler.postDelayed(new Runnable() { 124 @Override 125 public void run() { 126 registerWithSystemUser(); 127 } 128 }, BIND_TO_SYSTEM_USER_RETRY_DELAY); 129 } 130 }; 131 132 // Only for secondary users, this is the service connection we use to connect to the system user 133 private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() { 134 @Override 135 public void onServiceConnected(ComponentName name, IBinder service) { 136 if (service != null) { 137 mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface( 138 service); 139 EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION, 140 EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND, 141 sSystemServicesProxy.getProcessUser()); 142 143 // Listen for system user's death, so that we can reconnect later 144 try { 145 service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0); 146 } catch (RemoteException e) { 147 Log.e(TAG, "Lost connection to (System) SystemUI", e); 148 } 149 150 // Run each of the queued runnables 151 runAndFlushOnConnectRunnables(); 152 } 153 154 // Unbind ourselves now that we've registered our callbacks. The 155 // binder to the system user are still valid at this point. 156 mContext.unbindService(this); 157 } 158 159 @Override 160 public void onServiceDisconnected(ComponentName name) { 161 // Do nothing 162 } 163 }; 164 165 /** 166 * Returns the callbacks interface that non-system users can call. 167 */ getSystemUserCallbacks()168 public IBinder getSystemUserCallbacks() { 169 return mSystemToUserCallbacks; 170 } 171 getTaskLoader()172 public static RecentsTaskLoader getTaskLoader() { 173 return sTaskLoader; 174 } 175 176 getSystemServices()177 public static SystemServicesProxy getSystemServices() { 178 return sSystemServicesProxy; 179 } 180 getConfiguration()181 public static RecentsConfiguration getConfiguration() { 182 return sConfiguration; 183 } 184 getDebugFlags()185 public static RecentsDebugFlags getDebugFlags() { 186 return sDebugFlags; 187 } 188 189 @Override onStart(Context context, SysUiServiceProvider sysUiServiceProvider)190 public void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) { 191 mContext = context; 192 mSysUiServiceProvider = sysUiServiceProvider; 193 final Resources res = mContext.getResources(); 194 final int defaultTaskBarBackgroundColor = 195 mContext.getColor(R.color.recents_task_bar_default_background_color); 196 final int defaultTaskViewBackgroundColor = 197 mContext.getColor(R.color.recents_task_view_default_background_color); 198 sDebugFlags = new RecentsDebugFlags(); 199 sSystemServicesProxy = SystemServicesProxy.getInstance(mContext); 200 sConfiguration = new RecentsConfiguration(mContext); 201 sTaskLoader = new RecentsTaskLoader(mContext, 202 // TODO: Once we start building the AAR, move these into the loader 203 res.getInteger(R.integer.config_recents_max_thumbnail_count), 204 res.getInteger(R.integer.config_recents_max_icon_count), 205 res.getInteger(R.integer.recents_svelte_level)); 206 sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor); 207 mHandler = new Handler(); 208 mImpl = new RecentsImpl(mContext); 209 210 // Register with the event bus 211 EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); 212 EventBus.getDefault().register(sSystemServicesProxy, EVENT_BUS_PRIORITY); 213 EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY); 214 215 // Due to the fact that RecentsActivity is per-user, we need to establish and interface for 216 // the system user's Recents component to pass events (like show/hide/toggleRecents) to the 217 // secondary user, and vice versa (like visibility change, screen pinning). 218 final int processUser = sSystemServicesProxy.getProcessUser(); 219 if (sSystemServicesProxy.isSystemUser(processUser)) { 220 // For the system user, initialize an instance of the interface that we can pass to the 221 // secondary user 222 mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl); 223 } else { 224 // For the secondary user, bind to the primary user's service to get a persistent 225 // interface to register its implementation and to later update its state 226 registerWithSystemUser(); 227 } 228 } 229 230 @Override onBootCompleted()231 public void onBootCompleted() { 232 mImpl.onBootCompleted(); 233 } 234 235 236 @Override growRecents()237 public void growRecents() { 238 EventBus.getDefault().send(new RecentsGrowingEvent()); 239 } 240 241 /** 242 * Shows the Recents. 243 */ 244 @Override showRecentApps(boolean triggeredFromAltTab)245 public void showRecentApps(boolean triggeredFromAltTab) { 246 ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); 247 int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents(); 248 int currentUser = sSystemServicesProxy.getCurrentUser(); 249 if (sSystemServicesProxy.isSystemUser(currentUser)) { 250 mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */, 251 true /* animate */, recentsGrowTarget); 252 } else { 253 if (mSystemToUserCallbacks != null) { 254 IRecentsNonSystemUserCallbacks callbacks = 255 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 256 if (callbacks != null) { 257 try { 258 callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */, 259 true /* animate */, recentsGrowTarget); 260 } catch (RemoteException e) { 261 Log.e(TAG, "Callback failed", e); 262 } 263 } else { 264 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 265 } 266 } 267 } 268 } 269 270 /** 271 * Hides the Recents. 272 */ 273 @Override hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)274 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 275 int currentUser = sSystemServicesProxy.getCurrentUser(); 276 if (sSystemServicesProxy.isSystemUser(currentUser)) { 277 mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey); 278 } else { 279 if (mSystemToUserCallbacks != null) { 280 IRecentsNonSystemUserCallbacks callbacks = 281 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 282 if (callbacks != null) { 283 try { 284 callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey); 285 } catch (RemoteException e) { 286 Log.e(TAG, "Callback failed", e); 287 } 288 } else { 289 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 290 } 291 } 292 } 293 } 294 295 /** 296 * Toggles the Recents activity. 297 */ 298 @Override toggleRecentApps()299 public void toggleRecentApps() { 300 int growTarget = getComponent(Divider.class).getView().growsRecents(); 301 int currentUser = sSystemServicesProxy.getCurrentUser(); 302 if (sSystemServicesProxy.isSystemUser(currentUser)) { 303 mImpl.toggleRecents(growTarget); 304 } else { 305 if (mSystemToUserCallbacks != null) { 306 IRecentsNonSystemUserCallbacks callbacks = 307 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 308 if (callbacks != null) { 309 try { 310 callbacks.toggleRecents(growTarget); 311 } catch (RemoteException e) { 312 Log.e(TAG, "Callback failed", e); 313 } 314 } else { 315 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 316 } 317 } 318 } 319 } 320 321 /** 322 * Preloads info for the Recents activity. 323 */ 324 @Override preloadRecentApps()325 public void preloadRecentApps() { 326 int currentUser = sSystemServicesProxy.getCurrentUser(); 327 if (sSystemServicesProxy.isSystemUser(currentUser)) { 328 mImpl.preloadRecents(); 329 } else { 330 if (mSystemToUserCallbacks != null) { 331 IRecentsNonSystemUserCallbacks callbacks = 332 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 333 if (callbacks != null) { 334 try { 335 callbacks.preloadRecents(); 336 } catch (RemoteException e) { 337 Log.e(TAG, "Callback failed", e); 338 } 339 } else { 340 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 341 } 342 } 343 } 344 } 345 346 @Override cancelPreloadRecentApps()347 public void cancelPreloadRecentApps() { 348 int currentUser = sSystemServicesProxy.getCurrentUser(); 349 if (sSystemServicesProxy.isSystemUser(currentUser)) { 350 mImpl.cancelPreloadingRecents(); 351 } else { 352 if (mSystemToUserCallbacks != null) { 353 IRecentsNonSystemUserCallbacks callbacks = 354 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 355 if (callbacks != null) { 356 try { 357 callbacks.cancelPreloadingRecents(); 358 } catch (RemoteException e) { 359 Log.e(TAG, "Callback failed", e); 360 } 361 } else { 362 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 363 } 364 } 365 } 366 } 367 368 @Override splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction)369 public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction) { 370 Point realSize = new Point(); 371 if (initialBounds == null) { 372 mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) 373 .getRealSize(realSize); 374 initialBounds = new Rect(0, 0, realSize.x, realSize.y); 375 } 376 377 int currentUser = sSystemServicesProxy.getCurrentUser(); 378 ActivityManager.RunningTaskInfo runningTask = 379 ActivityManagerWrapper.getInstance().getRunningTask(); 380 final int activityType = runningTask != null 381 ? runningTask.configuration.windowConfiguration.getActivityType() 382 : ACTIVITY_TYPE_UNDEFINED; 383 boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive(); 384 boolean isRunningTaskInHomeOrRecentsStack = 385 activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS; 386 if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) { 387 logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode); 388 if (runningTask.supportsSplitScreenMultiWindow) { 389 if (metricsDockAction != -1) { 390 MetricsLogger.action(mContext, metricsDockAction, 391 runningTask.topActivity.flattenToShortString()); 392 } 393 if (sSystemServicesProxy.isSystemUser(currentUser)) { 394 mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds); 395 } else { 396 if (mSystemToUserCallbacks != null) { 397 IRecentsNonSystemUserCallbacks callbacks = 398 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 399 if (callbacks != null) { 400 try { 401 callbacks.splitPrimaryTask(runningTask.id, stackCreateMode, 402 initialBounds); 403 } catch (RemoteException e) { 404 Log.e(TAG, "Callback failed", e); 405 } 406 } else { 407 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 408 } 409 } 410 } 411 412 return true; 413 } else { 414 EventBus.getDefault().send(new ShowUserToastEvent( 415 R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT)); 416 return false; 417 } 418 } else { 419 return false; 420 } 421 } 422 logDockAttempt(Context ctx, ComponentName activity, int resizeMode)423 public static void logDockAttempt(Context ctx, ComponentName activity, int resizeMode) { 424 if (resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE) { 425 MetricsLogger.action(ctx, MetricsEvent.ACTION_WINDOW_DOCK_UNRESIZABLE, 426 activity.flattenToShortString()); 427 } 428 MetricsLogger.count(ctx, getMetricsCounterForResizeMode(resizeMode), 1); 429 } 430 getMetricsCounterForResizeMode(int resizeMode)431 private static String getMetricsCounterForResizeMode(int resizeMode) { 432 switch (resizeMode) { 433 case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE: 434 return COUNTER_WINDOW_UNSUPPORTED; 435 case ActivityInfo.RESIZE_MODE_RESIZEABLE: 436 case ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION: 437 return COUNTER_WINDOW_SUPPORTED; 438 default: 439 return COUNTER_WINDOW_INCOMPATIBLE; 440 } 441 } 442 443 @Override onAppTransitionFinished()444 public void onAppTransitionFinished() { 445 if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice) { 446 // Fallback, reset the flag once an app transition ends 447 EventBus.getDefault().send(new SetWaitingForTransitionStartEvent( 448 false /* waitingForTransitionStart */)); 449 } 450 } 451 452 /** 453 * Updates on configuration change. 454 */ onConfigurationChanged(Configuration newConfig)455 public void onConfigurationChanged(Configuration newConfig) { 456 int currentUser = sSystemServicesProxy.getCurrentUser(); 457 if (sSystemServicesProxy.isSystemUser(currentUser)) { 458 mImpl.onConfigurationChanged(); 459 } else { 460 if (mSystemToUserCallbacks != null) { 461 IRecentsNonSystemUserCallbacks callbacks = 462 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 463 if (callbacks != null) { 464 try { 465 callbacks.onConfigurationChanged(); 466 } catch (RemoteException e) { 467 Log.e(TAG, "Callback failed", e); 468 } 469 } else { 470 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 471 } 472 } 473 } 474 } 475 476 /** 477 * Handle Recents activity visibility changed. 478 */ onBusEvent(final RecentsVisibilityChangedEvent event)479 public final void onBusEvent(final RecentsVisibilityChangedEvent event) { 480 SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices(); 481 int processUser = ssp.getProcessUser(); 482 if (ssp.isSystemUser(processUser)) { 483 mImpl.onVisibilityChanged(event.applicationContext, event.visible); 484 } else { 485 postToSystemUser(new Runnable() { 486 @Override 487 public void run() { 488 try { 489 mUserToSystemCallbacks.updateRecentsVisibility(event.visible); 490 } catch (RemoteException e) { 491 Log.e(TAG, "Callback failed", e); 492 } 493 } 494 }); 495 } 496 497 // This will catch the cases when a user launches from recents to another app 498 // (and vice versa) that is not in the recents stack (such as home or bugreport) and it 499 // would not reset the wait for transition flag. This will catch it and make sure that the 500 // flag is reset. 501 if (!event.visible) { 502 mImpl.setWaitingForTransitionStart(false); 503 } 504 } 505 onBusEvent(DockedFirstAnimationFrameEvent event)506 public final void onBusEvent(DockedFirstAnimationFrameEvent event) { 507 SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices(); 508 int processUser = ssp.getProcessUser(); 509 if (ssp.isSystemUser(processUser)) { 510 final Divider divider = getComponent(Divider.class); 511 if (divider != null) { 512 divider.onDockedFirstAnimationFrame(); 513 } 514 } else { 515 postToSystemUser(new Runnable() { 516 @Override 517 public void run() { 518 try { 519 mUserToSystemCallbacks.sendDockedFirstAnimationFrameEvent(); 520 } catch (RemoteException e) { 521 Log.e(TAG, "Callback failed", e); 522 } 523 } 524 }); 525 } 526 } 527 528 /** 529 * Handle screen pinning request. 530 */ onBusEvent(final ScreenPinningRequestEvent event)531 public final void onBusEvent(final ScreenPinningRequestEvent event) { 532 int processUser = sSystemServicesProxy.getProcessUser(); 533 if (sSystemServicesProxy.isSystemUser(processUser)) { 534 mImpl.onStartScreenPinning(event.applicationContext, event.taskId); 535 } else { 536 postToSystemUser(new Runnable() { 537 @Override 538 public void run() { 539 try { 540 mUserToSystemCallbacks.startScreenPinning(event.taskId); 541 } catch (RemoteException e) { 542 Log.e(TAG, "Callback failed", e); 543 } 544 } 545 }); 546 } 547 } 548 onBusEvent(final RecentsDrawnEvent event)549 public final void onBusEvent(final RecentsDrawnEvent event) { 550 int processUser = sSystemServicesProxy.getProcessUser(); 551 if (sSystemServicesProxy.isSystemUser(processUser)) { 552 final Divider divider = getComponent(Divider.class); 553 if (divider != null) { 554 divider.onRecentsDrawn(); 555 } 556 } else { 557 postToSystemUser(new Runnable() { 558 @Override 559 public void run() { 560 try { 561 mUserToSystemCallbacks.sendRecentsDrawnEvent(); 562 } catch (RemoteException e) { 563 Log.e(TAG, "Callback failed", e); 564 } 565 } 566 }); 567 } 568 } 569 onBusEvent(final DockedTopTaskEvent event)570 public final void onBusEvent(final DockedTopTaskEvent event) { 571 int processUser = sSystemServicesProxy.getProcessUser(); 572 if (sSystemServicesProxy.isSystemUser(processUser)) { 573 final Divider divider = getComponent(Divider.class); 574 if (divider != null) { 575 divider.onDockedTopTask(); 576 } 577 } else { 578 postToSystemUser(new Runnable() { 579 @Override 580 public void run() { 581 try { 582 mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect); 583 } catch (RemoteException e) { 584 Log.e(TAG, "Callback failed", e); 585 } 586 } 587 }); 588 } 589 } 590 onBusEvent(final RecentsActivityStartingEvent event)591 public final void onBusEvent(final RecentsActivityStartingEvent event) { 592 int processUser = sSystemServicesProxy.getProcessUser(); 593 if (sSystemServicesProxy.isSystemUser(processUser)) { 594 final Divider divider = getComponent(Divider.class); 595 if (divider != null) { 596 divider.onRecentsActivityStarting(); 597 } 598 } else { 599 postToSystemUser(new Runnable() { 600 @Override 601 public void run() { 602 try { 603 mUserToSystemCallbacks.sendLaunchRecentsEvent(); 604 } catch (RemoteException e) { 605 Log.e(TAG, "Callback failed", e); 606 } 607 } 608 }); 609 } 610 } 611 onBusEvent(LaunchTaskFailedEvent event)612 public final void onBusEvent(LaunchTaskFailedEvent event) { 613 // Reset the transition when tasks fail to launch 614 mImpl.setWaitingForTransitionStart(false); 615 } 616 onBusEvent(ConfigurationChangedEvent event)617 public final void onBusEvent(ConfigurationChangedEvent event) { 618 // Update the configuration for the Recents component when the activity configuration 619 // changes as well 620 mImpl.onConfigurationChanged(); 621 } 622 onBusEvent(ShowUserToastEvent event)623 public final void onBusEvent(ShowUserToastEvent event) { 624 int currentUser = sSystemServicesProxy.getCurrentUser(); 625 if (sSystemServicesProxy.isSystemUser(currentUser)) { 626 mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength); 627 } else { 628 if (mSystemToUserCallbacks != null) { 629 IRecentsNonSystemUserCallbacks callbacks = 630 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); 631 if (callbacks != null) { 632 try { 633 callbacks.showCurrentUserToast(event.msgResId, event.msgLength); 634 } catch (RemoteException e) { 635 Log.e(TAG, "Callback failed", e); 636 } 637 } else { 638 Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser); 639 } 640 } 641 } 642 } 643 onBusEvent(SetWaitingForTransitionStartEvent event)644 public final void onBusEvent(SetWaitingForTransitionStartEvent event) { 645 int processUser = sSystemServicesProxy.getProcessUser(); 646 if (sSystemServicesProxy.isSystemUser(processUser)) { 647 mImpl.setWaitingForTransitionStart(event.waitingForTransitionStart); 648 } else { 649 postToSystemUser(new Runnable() { 650 @Override 651 public void run() { 652 try { 653 mUserToSystemCallbacks.setWaitingForTransitionStartEvent( 654 event.waitingForTransitionStart); 655 } catch (RemoteException e) { 656 Log.e(TAG, "Callback failed", e); 657 } 658 } 659 }); 660 } 661 } 662 onBusEvent(ExpandPipEvent event)663 public final void onBusEvent(ExpandPipEvent event) { 664 PipUI pipUi = getComponent(PipUI.class); 665 if (pipUi == null) { 666 return; 667 } 668 pipUi.expandPip(); 669 } 670 onBusEvent(HidePipMenuEvent event)671 public final void onBusEvent(HidePipMenuEvent event) { 672 PipUI pipUi = getComponent(PipUI.class); 673 if (pipUi == null) { 674 return; 675 } 676 event.getAnimationTrigger().increment(); 677 pipUi.hidePipMenu(() -> { 678 event.getAnimationTrigger().increment(); 679 }, () -> { 680 event.getAnimationTrigger().decrement(); 681 }); 682 event.getAnimationTrigger().decrement(); 683 } 684 685 /** 686 * Attempts to register with the system user. 687 */ registerWithSystemUser()688 private void registerWithSystemUser() { 689 final int processUser = sSystemServicesProxy.getProcessUser(); 690 postToSystemUser(new Runnable() { 691 @Override 692 public void run() { 693 try { 694 mUserToSystemCallbacks.registerNonSystemUserCallbacks( 695 new RecentsImplProxy(mImpl), processUser); 696 } catch (RemoteException e) { 697 Log.e(TAG, "Failed to register", e); 698 } 699 } 700 }); 701 } 702 703 /** 704 * Runs the runnable in the system user's Recents context, connecting to the service if 705 * necessary. 706 */ postToSystemUser(final Runnable onConnectRunnable)707 private void postToSystemUser(final Runnable onConnectRunnable) { 708 mOnConnectRunnables.add(onConnectRunnable); 709 if (mUserToSystemCallbacks == null) { 710 Intent systemUserServiceIntent = new Intent(); 711 systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class); 712 boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent, 713 mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); 714 EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION, 715 EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE, 716 sSystemServicesProxy.getProcessUser()); 717 if (!bound) { 718 // Retry after a fixed duration 719 mHandler.postDelayed(new Runnable() { 720 @Override 721 public void run() { 722 registerWithSystemUser(); 723 } 724 }, BIND_TO_SYSTEM_USER_RETRY_DELAY); 725 } 726 } else { 727 runAndFlushOnConnectRunnables(); 728 } 729 } 730 731 /** 732 * Runs all the queued runnables after a service connection is made. 733 */ runAndFlushOnConnectRunnables()734 private void runAndFlushOnConnectRunnables() { 735 for (Runnable r : mOnConnectRunnables) { 736 r.run(); 737 } 738 mOnConnectRunnables.clear(); 739 } 740 getComponent(Class<T> clazz)741 private <T> T getComponent(Class<T> clazz) { 742 return mSysUiServiceProvider.getComponent(clazz); 743 } 744 745 @Override dump(PrintWriter pw)746 public void dump(PrintWriter pw) { 747 pw.println("Recents"); 748 pw.println(" currentUserId=" + SystemServicesProxy.getInstance(mContext).getCurrentUser()); 749 } 750 } 751