/** Prepares the header bar layout. */
  void reloadHeaderBarLayout() {
    Resources res = mContext.getResources();
    mWindowRect = mSystemServicesProxy.getWindowRect();
    mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
    mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
    mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
    mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
    mConfig.updateOnConfigurationChange();
    Rect searchBarBounds = new Rect();
    // Try and pre-emptively bind the search widget on startup to ensure that we
    // have the right thumbnail bounds to animate to.
    // Note: We have to reload the widget id before we get the task stack bounds below
    if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
      mConfig.getSearchBarBounds(
          mWindowRect.width(), mWindowRect.height(), mStatusBarHeight, searchBarBounds);
    }
    mConfig.getAvailableTaskStackBounds(
        mWindowRect.width(),
        mWindowRect.height(),
        mStatusBarHeight,
        (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
        searchBarBounds,
        mTaskStackBounds);
    if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
      mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
    } else {
      mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
    }

    // Inflate the header bar layout so that we can rebind and draw it for the transition
    TaskStack stack = new TaskStack();
    mDummyStackView = new TaskStackView(mContext, stack);
    TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
    Rect taskStackBounds = new Rect(mTaskStackBounds);
    taskStackBounds.bottom -= mSystemInsets.bottom;
    algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
    Rect taskViewSize = algo.getUntransformedTaskViewSize();
    int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
    synchronized (mHeaderBarLock) {
      mHeaderBar =
          (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, false);
      mHeaderBar.measure(
          View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
          View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
      mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
    }
  }
  /** Starts the recents activity */
  void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
    RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
    RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);

    if (sInstanceLoadPlan == null) {
      // Create a new load plan if onPreloadRecents() was never triggered
      sInstanceLoadPlan = loader.createLoadPlan(mContext);
    }

    // Temporarily skip the transition (use a dummy fade) if multi stack is enabled.
    // For multi-stack we need to figure out where each of the tasks are going.
    if (mConfig.multiStackEnabled) {
      loader.preloadTasks(sInstanceLoadPlan, true);
      ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
      TaskStack stack = stacks.get(0);
      mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
      TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
          mDummyStackView.computeStackVisibilityReport();
      ActivityOptions opts = getUnknownTransitionActivityOptions();
      startAlternateRecentsActivity(
          topTask,
          opts,
          true /* fromHome */,
          false /* fromSearchHome */,
          false /* fromThumbnail */,
          stackVr);
      return;
    }

    if (!sInstanceLoadPlan.hasTasks()) {
      loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
    }
    ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
    TaskStack stack = stacks.get(0);

    // Prepare the dummy stack for the transition
    mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
    TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
        mDummyStackView.computeStackVisibilityReport();
    boolean hasRecentTasks = stack.getTaskCount() > 0;
    boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;

    if (useThumbnailTransition) {

      // Try starting with a thumbnail transition
      ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, mDummyStackView);
      if (opts != null) {
        startAlternateRecentsActivity(
            topTask,
            opts,
            false /* fromHome */,
            false /* fromSearchHome */,
            true /* fromThumbnail */,
            stackVr);
      } else {
        // Fall through below to the non-thumbnail transition
        useThumbnailTransition = false;
      }
    }

    if (!useThumbnailTransition) {
      // If there is no thumbnail transition, but is launching from home into recents, then
      // use a quick home transition and do the animation from home
      if (hasRecentTasks) {
        String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
        String searchWidgetPackage =
            Prefs.getString(mContext, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);

        // Determine whether we are coming from a search owned home activity
        boolean fromSearchHome =
            (homeActivityPackage != null) && homeActivityPackage.equals(searchWidgetPackage);
        ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
        startAlternateRecentsActivity(
            topTask, opts, true /* fromHome */, fromSearchHome, false /* fromThumbnail */, stackVr);
      } else {
        // Otherwise we do the normal fade from an unknown source
        ActivityOptions opts = getUnknownTransitionActivityOptions();
        startAlternateRecentsActivity(
            topTask,
            opts,
            true /* fromHome */,
            false /* fromSearchHome */,
            false /* fromThumbnail */,
            stackVr);
      }
    }
    mLastToggleTime = SystemClock.elapsedRealtime();
  }