/** Requests all task stacks to start their exit-recents animation */
  public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
      View child = getChildAt(i);
      if (child != mSearchBar) {
        TaskStackView stackView = (TaskStackView) child;
        stackView.startExitToHomeAnimation(ctx);
      }
    }

    // Notify of the exit animation
    mCb.onExitToHomeAnimationTriggered();
  }
Exemplo n.º 2
0
  @Override
  public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks) {
    if (removedTasks != null) {
      int taskCount = removedTasks.size();
      for (int i = 0; i < taskCount; i++) {
        onTaskViewDismissed(removedTasks.get(i));
      }
    }

    mCb.onAllTaskViewsDismissed();

    // Keep track of all-deletions
    MetricsLogger.count(getContext(), "overview_task_all_dismissed", 1);
  }
Exemplo n.º 3
0
  /** Requests all task stacks to start their exit-recents animation */
  public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
    Log.d(TAG, "startExitToHomeAnimation: ");
    // We have to increment/decrement the post animation trigger in case there are no children
    // to ensure that it runs
    ctx.postAnimationTrigger.increment();
    List<TaskStackView> stackViews = getTaskStackViews();
    int stackCount = stackViews.size();
    for (int i = 0; i < stackCount; i++) {
      TaskStackView stackView = stackViews.get(i);
      stackView.startExitToHomeAnimation(ctx);
    }
    ctx.postAnimationTrigger.decrement();

    // Notify of the exit animation
    mCb.onExitToHomeAnimationTriggered();
  }
 @Override
 public void onAllTaskViewsDismissed() {
   mCb.onAllTaskViewsDismissed();
 }
  /** ** TaskStackView.TaskStackCallbacks Implementation *** */
  @Override
  public void onTaskViewClicked(
      final TaskStackView stackView,
      final TaskView tv,
      final TaskStack stack,
      final Task task,
      final boolean lockToTask) {
    // Notify any callbacks of the launching of a new task
    if (mCb != null) {
      mCb.onTaskViewClicked();
    }
    // Skip if we are already launching tasks
    if (mAlreadyLaunchingTask) {
      return;
    }
    mAlreadyLaunchingTask = true;

    // Upfront the processing of the thumbnail
    TaskViewTransform transform = new TaskViewTransform();
    View sourceView;
    int offsetX = 0;
    int offsetY = 0;
    float stackScroll = stackView.getScroller().getStackScroll();
    if (tv == null) {
      // If there is no actual task view, then use the stack view as the source view
      // and then offset to the expected transform rect, but bound this to just
      // outside the display rect (to ensure we don't animate from too far away)
      sourceView = stackView;
      transform =
          stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
      offsetX = transform.rect.left;
      offsetY = mConfig.displayRect.height();
    } else {
      sourceView = tv.mThumbnailView;
      transform =
          stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
    }

    // Compute the thumbnail to scale up from
    final SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
    ActivityOptions opts = null;
    if (task.thumbnail != null && task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
      Bitmap b;
      if (tv != null) {
        // Disable any focused state before we draw the header
        if (tv.isFocusedTask()) {
          tv.unsetFocusedTask();
        }

        float scale = tv.getScaleX();
        int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale);
        int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale);
        b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight, Bitmap.Config.ARGB_8888);
        if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
          b.eraseColor(0xFFff0000);
        } else {
          Canvas c = new Canvas(b);
          c.scale(tv.getScaleX(), tv.getScaleY());
          tv.mHeaderView.draw(c);
          c.setBitmap(null);
        }
      } else {
        // Notify the system to skip the thumbnail layer by using an ALPHA_8 bitmap
        b = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
      }
      ActivityOptions.OnAnimationStartedListener animStartedListener = null;
      if (lockToTask) {
        animStartedListener =
            new ActivityOptions.OnAnimationStartedListener() {
              boolean mTriggered = false;

              @Override
              public void onAnimationStarted() {
                if (!mTriggered) {
                  postDelayed(
                      new Runnable() {
                        @Override
                        public void run() {
                          ssp.lockCurrentTask();
                        }
                      },
                      350);
                  mTriggered = true;
                }
              }
            };
      }
      opts =
          ActivityOptions.makeThumbnailAspectScaleUpAnimation(
              sourceView,
              b,
              offsetX,
              offsetY,
              transform.rect.width(),
              transform.rect.height(),
              animStartedListener);
    }

    final ActivityOptions launchOpts = opts;
    final Runnable launchRunnable =
        new Runnable() {
          @Override
          public void run() {
            if (task.isActive) {
              // Bring an active task to the foreground
              ssp.moveTaskToFront(task.key.id, launchOpts);
            } else {
              if (ssp.startActivityFromRecents(
                  getContext(), task.key.id, task.activityLabel, launchOpts)) {
                if (launchOpts == null && lockToTask) {
                  ssp.lockCurrentTask();
                }
              } else {
                // Dismiss the task and return the user to home if we fail to
                // launch the task
                onTaskViewDismissed(task);
                if (mCb != null) {
                  mCb.onTaskLaunchFailed();
                }
              }
            }
          }
        };

    // Launch the app right away if there is no task view, otherwise, animate the icon out first
    if (tv == null) {
      post(launchRunnable);
    } else {
      if (!task.group.isFrontMostTask(task)) {
        // For affiliated tasks that are behind other tasks, we must animate the front cards
        // out of view before starting the task transition
        stackView.startLaunchTaskAnimation(tv, launchRunnable, lockToTask);
      } else {
        // Otherwise, we can start the task transition immediately
        stackView.startLaunchTaskAnimation(tv, null, lockToTask);
        postDelayed(launchRunnable, 17);
      }
    }
  }
Exemplo n.º 6
0
 @Override
 public void onTaskResize(Task t) {
   if (mCb != null) {
     mCb.onTaskResize(t);
   }
 }
Exemplo n.º 7
0
  /** ** TaskStackView.TaskStackCallbacks Implementation *** */
  @Override
  public void onTaskViewClicked(
      final TaskStackView stackView,
      final TaskView tv,
      final TaskStack stack,
      final Task task,
      final boolean lockToTask) {
    Log.d(TAG, "onTaskViewClicked: ");
    // Notify any callbacks of the launching of a new task
    if (mCb != null) {
      mCb.onTaskViewClicked();
    }

    // Upfront the processing of the thumbnail
    TaskViewTransform transform = new TaskViewTransform();
    View sourceView;
    int offsetX = 0;
    int offsetY = 0;
    float stackScroll = stackView.getScroller().getStackScroll();
    if (tv == null) {
      // If there is no actual task view, then use the stack view as the source view
      // and then offset to the expected transform rect, but bound this to just
      // outside the display rect (to ensure we don't animate from too far away)
      sourceView = stackView;
      transform =
          stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
      offsetX = transform.rect.left;
      offsetY = mConfig.displayRect.height();
    } else {
      sourceView = tv.mThumbnailView;
      transform =
          stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
    }

    // Compute the thumbnail to scale up from
    final SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
    ActivityOptions opts = null;
    if (task.thumbnail != null && task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
      ActivityOptions.OnAnimationStartedListener animStartedListener = null;
      if (lockToTask) {
        animStartedListener =
            new ActivityOptions.OnAnimationStartedListener() {
              boolean mTriggered = false;

              @Override
              public void onAnimationStarted() {
                if (!mTriggered) {
                  postDelayed(
                      new Runnable() {
                        @Override
                        public void run() {
                          mCb.onScreenPinningRequest();
                        }
                      },
                      350);
                  mTriggered = true;
                }
              }
            };
      }
      if (tv != null) {
        postDrawHeaderThumbnailTransitionRunnable(
            tv, offsetX, offsetY, transform, animStartedListener);
      }
      if (mConfig.multiStackEnabled) {
        opts =
            ActivityOptions.makeCustomAnimation(
                sourceView.getContext(),
                R.anim.recents_from_unknown_enter,
                R.anim.recents_from_unknown_exit,
                sourceView.getHandler(),
                animStartedListener);
      } else {
        opts =
            ActivityOptions.makeThumbnailAspectScaleUpAnimation(
                sourceView,
                Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
                offsetX,
                offsetY,
                transform.rect.width(),
                transform.rect.height(),
                sourceView.getHandler(),
                animStartedListener);
      }
    }

    final ActivityOptions launchOpts = opts;
    final Runnable launchRunnable =
        new Runnable() {
          @Override
          public void run() {
            if (task.isActive) {
              // Bring an active task to the foreground
              ssp.moveTaskToFront(task.key.id, launchOpts);
            } else {
              if (ssp.startActivityFromRecents(
                  getContext(), task.key.id, task.activityLabel, launchOpts)) {
                if (launchOpts == null && lockToTask) {
                  mCb.onScreenPinningRequest();
                }
              } else {
                // Dismiss the task and return the user to home if we fail to
                // launch the task
                onTaskViewDismissed(task);
                if (mCb != null) {
                  mCb.onTaskLaunchFailed();
                }

                // Keep track of failed launches
                MetricsLogger.count(getContext(), "overview_task_launch_failed", 1);
              }
            }
          }
        };

    // Keep track of the index of the task launch
    int taskIndexFromFront = 0;
    int taskIndex = stack.indexOfTask(task);
    if (taskIndex > -1) {
      taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
    }
    MetricsLogger.histogram(getContext(), "overview_task_launch_index", taskIndexFromFront);

    // Launch the app right away if there is no task view, otherwise, animate the icon out first
    if (tv == null) {
      launchRunnable.run();
    } else {
      if (task.group != null && !task.group.isFrontMostTask(task)) {
        // For affiliated tasks that are behind other tasks, we must animate the front cards
        // out of view before starting the task transition
        stackView.startLaunchTaskAnimation(tv, launchRunnable, lockToTask);
      } else {
        // Otherwise, we can start the task transition immediately
        stackView.startLaunchTaskAnimation(tv, null, lockToTask);
        launchRunnable.run();
      }
    }
  }
Exemplo n.º 8
0
  private void postDrawHeaderThumbnailTransitionRunnable(
      final TaskView tv,
      final int offsetX,
      final int offsetY,
      final TaskViewTransform transform,
      final ActivityOptions.OnAnimationStartedListener animStartedListener) {
    Runnable r =
        new Runnable() {
          @Override
          public void run() {
            // Disable any focused state before we draw the header
            if (tv.isFocusedTask()) {
              tv.unsetFocusedTask();
            }

            float scale = tv.getScaleX();
            int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale);
            int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale);

            Bitmap b =
                Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight, Bitmap.Config.ARGB_8888);
            if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
              b.eraseColor(0xFFff0000);
            } else {
              Canvas c = new Canvas(b);
              c.scale(tv.getScaleX(), tv.getScaleY());
              tv.mHeaderView.draw(c);
              c.setBitmap(null);
            }
            b = b.createAshmemBitmap();
            int[] pts = new int[2];
            tv.getLocationOnScreen(pts);
            try {
              WindowManagerGlobal.getWindowManagerService()
                  .overridePendingAppTransitionAspectScaledThumb(
                      b,
                      pts[0] + offsetX,
                      pts[1] + offsetY,
                      transform.rect.width(),
                      transform.rect.height(),
                      new IRemoteCallback.Stub() {
                        @Override
                        public void sendResult(Bundle data) throws RemoteException {
                          post(
                              new Runnable() {
                                @Override
                                public void run() {
                                  if (animStartedListener != null) {
                                    animStartedListener.onAnimationStarted();
                                  }
                                }
                              });
                        }
                      },
                      true);
            } catch (RemoteException e) {
              Log.w(TAG, "Error overriding app transition", e);
            }
          }
        };
    mCb.runAfterPause(r);
  }