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