content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.quickstep.views;
  
  import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
  import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
  
  import android.animation.Animator;
  import android.animation.AnimatorSet;
  import android.animation.ObjectAnimator;
  import android.content.Context;
  import android.graphics.Rect;
  import android.graphics.drawable.Drawable;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.Gravity;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.LinearLayout;
  import android.widget.TextView;
  
  import com.android.launcher3.AbstractFloatingView;
  import com.android.launcher3.BaseDraggingActivity;
  import com.android.launcher3.FastBitmapDrawable;
  import com.android.launcher3.R;
  import com.android.launcher3.anim.AnimationSuccessListener;
  import com.android.launcher3.anim.Interpolators;
  import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
  import com.android.launcher3.testing.TestProtocol;
  import com.android.launcher3.util.Themes;
  import com.android.launcher3.views.BaseDragLayer;
  import com.android.quickstep.TaskOverlayFactory;
  import com.android.quickstep.TaskSystemShortcut;
  import com.android.quickstep.TaskUtils;
  import com.android.quickstep.views.IconView.OnScaleUpdateListener;
  
  import java.util.List;
  
  /**
   * Contains options for a recent task when long-pressing its icon.
   */
  public class TaskMenuView extends AbstractFloatingView {
  
      private static final Rect sTempRect = new Rect();
  
      private final OnScaleUpdateListener mTaskViewIconScaleListener = new OnScaleUpdateListener() {
          @Override
          public void onScaleUpdate(float scale) {
              final Drawable drawable = mTaskIcon.getDrawable();
              if (drawable instanceof FastBitmapDrawable) {
                  if (scale != ((FastBitmapDrawable) drawable).getScale()) {
                      mMenuIconDrawable.setScale(scale);
                  }
              }
          }
      };
  
      private final OnScaleUpdateListener mMenuIconScaleListener = new OnScaleUpdateListener() {
          @Override
          public void onScaleUpdate(float scale) {
              final Drawable taskViewDrawable = mTaskView.getIconView().getDrawable();
              if (taskViewDrawable instanceof FastBitmapDrawable) {
                  final float currentScale = ((FastBitmapDrawable) taskViewDrawable).getScale();
                  if (currentScale != scale) {
                      ((FastBitmapDrawable) taskViewDrawable).setScale(scale);
                  }
              }
          }
      };
  
      private static final int REVEAL_OPEN_DURATION = 150;
      private static final int REVEAL_CLOSE_DURATION = 100;
  
      private final float mThumbnailTopMargin;
      private BaseDraggingActivity mActivity;
      private TextView mTaskName;
      private IconView mTaskIcon;
      private AnimatorSet mOpenCloseAnimator;
      private TaskView mTaskView;
      private LinearLayout mOptionLayout;
      private FastBitmapDrawable mMenuIconDrawable;
  
      public TaskMenuView(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
  
          mActivity = BaseDraggingActivity.fromContext(context);
          mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
      }
  
      @Override
      protected void onFinishInflate() {
          super.onFinishInflate();
          mTaskName = findViewById(R.id.task_name);
          mTaskIcon = findViewById(R.id.task_icon);
          mOptionLayout = findViewById(R.id.menu_option_layout);
      }
  
      @Override
      public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
          if (ev.getAction() == MotionEvent.ACTION_DOWN) {
              BaseDragLayer dl = mActivity.getDragLayer();
              if (!dl.isEventOverView(this, ev)) {
                  // TODO: log this once we have a new container type for it?
                  close(true);
                  return true;
              }
          }
          return false;
      }
  
      @Override
      protected void handleClose(boolean animate) {
          if (animate) {
              animateClose();
          } else {
              closeComplete();
          }
      }
  
      @Override
      public void logActionCommand(int command) {
          // TODO
      }
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
  
          // Remove all scale listeners when menu is removed
          mTaskView.getIconView().removeUpdateScaleListener(mTaskViewIconScaleListener);
          mTaskIcon.removeUpdateScaleListener(mMenuIconScaleListener);
      }
  
      @Override
      protected boolean isOfType(int type) {
          return (type & TYPE_TASK_MENU) != 0;
      }
  
      public void setPosition(float x, float y) {
          setX(x);
          setY(y + mThumbnailTopMargin);
      }
  
      public static TaskMenuView showForTask(TaskView taskView) {
          BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
          final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
                          R.layout.task_menu, activity.getDragLayer(), false);
          return taskMenuView.populateAndShowForTask(taskView) ? taskMenuView : null;
      }
  
      private boolean populateAndShowForTask(TaskView taskView) {
          if (isAttachedToWindow()) {
              return false;
          }
          mActivity.getDragLayer().addView(this);
          mTaskView = taskView;
          addMenuOptions(mTaskView);
          orientAroundTaskView(mTaskView);
          post(this::animateOpen);
          return true;
      }
  
      private void addMenuOptions(TaskView taskView) {
          Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
          mTaskIcon.setDrawable(icon);
          mTaskIcon.setOnClickListener(v -> close(true));
          mTaskName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
          mTaskName.setOnClickListener(v -> close(true));
  
          // Set the icons to match scale by listening to each other's changes
          mMenuIconDrawable = icon instanceof FastBitmapDrawable ? (FastBitmapDrawable) icon : null;
          taskView.getIconView().addUpdateScaleListener(mTaskViewIconScaleListener);
          mTaskIcon.addUpdateScaleListener(mMenuIconScaleListener);
  
          // Move the icon and text up half an icon size to lay over the TaskView
          LinearLayout.LayoutParams params =
                  (LinearLayout.LayoutParams) mTaskIcon.getLayoutParams();
          params.topMargin = (int) -mThumbnailTopMargin;
          mTaskIcon.setLayoutParams(params);
  
          final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext());
          final List<TaskSystemShortcut> shortcuts =
                  TaskOverlayFactory.INSTANCE.get(getContext()).getEnabledShortcuts(taskView);
          final int count = shortcuts.size();
          for (int i = 0; i < count; ++i) {
              final TaskSystemShortcut menuOption = shortcuts.get(i);
              addMenuOption(menuOption, menuOption.getOnClickListener(activity, taskView));
          }
      }
  
      private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
          ViewGroup menuOptionView = (ViewGroup) mActivity.getLayoutInflater().inflate(
                  R.layout.task_view_menu_option, this, false);
          menuOption.setIconAndLabelFor(
                  menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
          menuOptionView.setOnClickListener(onClickListener);
          mOptionLayout.addView(menuOptionView);
      }
  
      private void orientAroundTaskView(TaskView taskView) {
          measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
          mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
          Rect insets = mActivity.getDragLayer().getInsets();
          BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
          params.width = taskView.getMeasuredWidth();
          params.gravity = Gravity.START;
          setLayoutParams(params);
          setScaleX(taskView.getScaleX());
          setScaleY(taskView.getScaleY());
          setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top);
      }
  
      private void animateOpen() {
          animateOpenOrClosed(false);
          mIsOpen = true;
      }
  
      private void animateClose() {
          animateOpenOrClosed(true);
      }
  
      private void animateOpenOrClosed(boolean closing) {
          if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
              mOpenCloseAnimator.end();
          }
          mOpenCloseAnimator = new AnimatorSet();
  
          final Animator revealAnimator = createOpenCloseOutlineProvider()
                  .createRevealAnimator(this, closing);
          revealAnimator.setInterpolator(Interpolators.DEACCEL);
          mOpenCloseAnimator.play(revealAnimator);
          mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA,
                  closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
          mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
              @Override
              public void onAnimationStart(Animator animation) {
                  setVisibility(VISIBLE);
              }
  
              @Override
              public void onAnimationSuccess(Animator animator) {
                  if (closing) {
                      closeComplete();
                  }
              }
          });
          mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
          mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION);
          mOpenCloseAnimator.start();
      }
  
      private void closeComplete() {
          mIsOpen = false;
          mActivity.getDragLayer().removeView(this);
      }
  
      private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
          float radius = Themes.getDialogCornerRadius(getContext());
          Rect fromRect = new Rect(0, 0, getWidth(), 0);
          Rect toRect = new Rect(0, 0, getWidth(), getHeight());
          return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
      }
  
      public View findMenuItemByText(String text) {
          for (int i = mOptionLayout.getChildCount() - 1; i >= 0; --i) {
              final ViewGroup menuOptionView = (ViewGroup) mOptionLayout.getChildAt(i);
              if (text.equals(menuOptionView.<TextView>findViewById(R.id.text).getText())) {
                  return menuOptionView;
              }
          }
          return null;
      }
  }
  