@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
    int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;

    // Measure the content
    mContent.measure(
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));

    // Measure the bar view, and action button
    mHeaderView.measure(
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
    mActionButtonView.measure(
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
        MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
    // Measure the thumbnail to be square
    mThumbnailView.measure(
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
    setMeasuredDimension(width, height);
    invalidateOutline();
  }
 /** Enables all focus animations. */
 void enableFocusAnimations() {
   boolean wasFocusAnimationsEnabled = mFocusAnimationsEnabled;
   mFocusAnimationsEnabled = true;
   if (mIsFocused && !wasFocusAnimationsEnabled) {
     // Re-notify the header if we were focused and animations were not previously enabled
     mHeaderView.onTaskViewFocusChanged(true, true);
   }
 }
  /** Unsets the focused task explicitly. */
  void unsetFocusedTask() {
    mIsFocused = false;
    if (mFocusAnimationsEnabled) {
      // Un-focus the header bar
      mHeaderView.onTaskViewFocusChanged(false, true);
    }

    // Update the thumbnail alpha with the focus
    mThumbnailView.onFocusChanged(false);
    // Call the callback
    if (mCb != null) {
      mCb.onTaskViewFocusChanged(this, false);
    }
    invalidate();
  }
  /** Animates this task view as it exits recents */
  void startLaunchTaskAnimation(
      final Runnable postAnimRunnable,
      boolean isLaunchingTask,
      boolean occludesLaunchTarget,
      boolean lockToTask) {
    if (isLaunchingTask) {
      // Animate the thumbnail alpha back into full opacity for the window animation out
      mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);

      // Animate the dim
      if (mDimAlpha > 0) {
        ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
        anim.setDuration(mConfig.taskViewExitToAppDuration);
        anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
        anim.start();
      }

      // Animate the action button away
      if (!lockToTask) {
        float toScale = 0.9f;
        mActionButtonView.animate().scaleX(toScale).scaleY(toScale);
      }
      mActionButtonView
          .animate()
          .alpha(0f)
          .setStartDelay(0)
          .setDuration(mConfig.taskViewExitToAppDuration)
          .setInterpolator(mConfig.fastOutLinearInInterpolator)
          .withLayer()
          .start();
    } else {
      // Hide the dismiss button
      mHeaderView.startLaunchTaskDismissAnimation();
      // If this is another view in the task grouping and is in front of the launch task,
      // animate it away first
      if (occludesLaunchTarget) {
        animate()
            .alpha(0f)
            .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx)
            .setStartDelay(0)
            .setUpdateListener(null)
            .setInterpolator(mConfig.fastOutLinearInInterpolator)
            .setDuration(mConfig.taskViewExitToAppDuration)
            .start();
      }
    }
  }
 @Override
 public void onTaskDataUnloaded() {
   if (mThumbnailView != null && mHeaderView != null) {
     // Unbind each of the views from the task data and remove the task callback
     mTask.setCallbacks(null);
     mThumbnailView.unbindFromTask();
     mHeaderView.unbindFromTask();
     // Unbind any listeners
     mHeaderView.mApplicationIcon.setOnClickListener(null);
     mHeaderView.mDismissButton.setOnClickListener(null);
     mActionButtonView.setOnClickListener(null);
     if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
       mHeaderView.mApplicationIcon.setOnLongClickListener(null);
     }
   }
   mTaskDataLoaded = false;
 }
 @Override
 public void onTaskDataLoaded() {
   if (mThumbnailView != null && mHeaderView != null) {
     // Bind each of the views to the new task data
     mThumbnailView.rebindToTask(mTask);
     mHeaderView.rebindToTask(mTask);
     // Rebind any listeners
     mHeaderView.mApplicationIcon.setOnClickListener(this);
     mHeaderView.mDismissButton.setOnClickListener(this);
     mActionButtonView.setOnClickListener(this);
     if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
       if (mConfig.developerOptionsEnabled) {
         mHeaderView.mApplicationIcon.setOnLongClickListener(this);
       }
     }
   }
   mTaskDataLoaded = true;
 }
 /** Returns the current dim. */
 public void setDim(int dim) {
   mDimAlpha = dim;
   if (mConfig.useHardwareLayers) {
     // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
     if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
       mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
       mDimLayerPaint.setColorFilter(mDimColorFilter);
       mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
     }
   } else {
     float dimAlpha = mDimAlpha / 255.0f;
     if (mThumbnailView != null) {
       mThumbnailView.setDimAlpha(dimAlpha);
     }
     if (mHeaderView != null) {
       mHeaderView.setDimAlpha(dim);
     }
   }
 }
 /**
  * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
  * if the view is not currently visible, or we are in touch state (where we still want to keep
  * track of focus).
  */
 public void setFocusedTask(boolean animateFocusedState) {
   mIsFocused = true;
   if (mFocusAnimationsEnabled) {
     // Focus the header bar
     mHeaderView.onTaskViewFocusChanged(true, animateFocusedState);
   }
   // Update the thumbnail alpha with the focus
   mThumbnailView.onFocusChanged(true);
   // Call the callback
   if (mCb != null) {
     mCb.onTaskViewFocusChanged(this, true);
   }
   // Workaround, we don't always want it focusable in touch mode, but we want the first task
   // to be focused after the enter-recents animation, which can be triggered from either touch
   // or keyboard
   setFocusableInTouchMode(true);
   requestFocus();
   setFocusableInTouchMode(false);
   invalidate();
 }
 /**
  * Resets the state tracking that the user has not interacted with the stack after a certain time.
  */
 void resetNoUserInteractionState() {
   mHeaderView.resetNoUserInteractionState();
 }
 /** Animates this task view if the user does not interact with the stack after a certain time. */
 void startNoUserInteractionAnimation() {
   mHeaderView.startNoUserInteractionAnimation();
 }