content: /*
   * Copyright (C) 2015 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.launcher3.allapps;
  
  import android.animation.ObjectAnimator;
  import android.content.Context;
  import android.content.res.Resources;
  import android.graphics.Canvas;
  import android.graphics.ColorFilter;
  import android.graphics.PixelFormat;
  import android.graphics.Rect;
  import android.graphics.drawable.Drawable;
  import android.view.ContextThemeWrapper;
  import android.view.Gravity;
  
  import com.android.launcher3.LauncherAnimUtils;
  import com.android.launcher3.R;
  import com.android.launcher3.util.Themes;
  
  /**
   * This is a custom composite drawable that has a fixed virtual size and dynamically lays out its
   * children images relatively within its bounds.  This way, we can reduce the memory usage of a
   * single, large sparsely populated image.
   */
  public class AllAppsBackgroundDrawable extends Drawable {
  
      /**
       * A helper class to position and orient a drawable to be drawn.
       */
      protected static class TransformedImageDrawable {
          private Drawable mImage;
          private float mXPercent;
          private float mYPercent;
          private int mGravity;
          private int mAlpha;
  
          /**
           * @param gravity If one of the Gravity center values, the x and y offset will take the width
           *                and height of the image into account to center the image to the offset.
           */
          public TransformedImageDrawable(Context context, int resourceId, float xPct, float yPct,
                  int gravity) {
              mImage = context.getDrawable(resourceId);
              mXPercent = xPct;
              mYPercent = yPct;
              mGravity = gravity;
          }
  
          public void setAlpha(int alpha) {
              mImage.setAlpha(alpha);
              mAlpha = alpha;
          }
  
          public int getAlpha() {
              return mAlpha;
          }
  
          public void updateBounds(Rect bounds) {
              int width = mImage.getIntrinsicWidth();
              int height = mImage.getIntrinsicHeight();
              int left = bounds.left + (int) (mXPercent * bounds.width());
              int top = bounds.top + (int) (mYPercent * bounds.height());
              if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
                  left -= (width / 2);
              }
              if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
                  top -= (height / 2);
              }
              mImage.setBounds(left, top, left + width, top + height);
          }
  
          public void draw(Canvas canvas) {
              mImage.draw(canvas);
          }
  
          public Rect getBounds() {
              return mImage.getBounds();
          }
      }
  
      protected final TransformedImageDrawable mHand;
      protected final TransformedImageDrawable[] mIcons;
      private final int mWidth;
      private final int mHeight;
  
      private ObjectAnimator mBackgroundAnim;
  
      public AllAppsBackgroundDrawable(Context context) {
          Resources res = context.getResources();
          mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width);
          mHeight = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_height);
  
          context = new ContextThemeWrapper(context,
                  Themes.getAttrBoolean(context, R.attr.isMainColorDark)
                          ? R.style.AllAppsEmptySearchBackground_Dark
                          : R.style.AllAppsEmptySearchBackground);
          mHand = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_hand,
                  0.575f, 0.f, Gravity.CENTER_HORIZONTAL);
          mIcons = new TransformedImageDrawable[4];
          mIcons[0] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_1,
                  0.375f, 0, Gravity.CENTER_HORIZONTAL);
          mIcons[1] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_2,
                  0.3125f, 0.2f, Gravity.CENTER_HORIZONTAL);
          mIcons[2] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_3,
                  0.475f, 0.26f, Gravity.CENTER_HORIZONTAL);
          mIcons[3] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_4,
                  0.7f, 0.125f, Gravity.CENTER_HORIZONTAL);
      }
  
      /**
       * Animates the background alpha.
       */
      public void animateBgAlpha(float finalAlpha, int duration) {
          int finalAlphaI = (int) (finalAlpha * 255f);
          if (getAlpha() != finalAlphaI) {
              mBackgroundAnim = cancelAnimator(mBackgroundAnim);
              mBackgroundAnim = ObjectAnimator.ofInt(this, LauncherAnimUtils.DRAWABLE_ALPHA,
                      finalAlphaI);
              mBackgroundAnim.setDuration(duration);
              mBackgroundAnim.start();
          }
      }
  
      /**
       * Sets the background alpha immediately.
       */
      public void setBgAlpha(float finalAlpha) {
          int finalAlphaI = (int) (finalAlpha * 255f);
          if (getAlpha() != finalAlphaI) {
              mBackgroundAnim = cancelAnimator(mBackgroundAnim);
              setAlpha(finalAlphaI);
          }
      }
  
      @Override
      public int getIntrinsicWidth() {
          return mWidth;
      }
  
      @Override
      public int getIntrinsicHeight() {
          return mHeight;
      }
  
      @Override
      public void draw(Canvas canvas) {
          mHand.draw(canvas);
          for (int i = 0; i < mIcons.length; i++) {
              mIcons[i].draw(canvas);
          }
      }
  
      @Override
      protected void onBoundsChange(Rect bounds) {
          super.onBoundsChange(bounds);
          mHand.updateBounds(bounds);
          for (int i = 0; i < mIcons.length; i++) {
              mIcons[i].updateBounds(bounds);
          }
          invalidateSelf();
      }
  
      @Override
      public void setAlpha(int alpha) {
          mHand.setAlpha(alpha);
          for (int i = 0; i < mIcons.length; i++) {
              mIcons[i].setAlpha(alpha);
          }
          invalidateSelf();
      }
  
      @Override
      public int getAlpha() {
          return mHand.getAlpha();
      }
  
      @Override
      public void setColorFilter(ColorFilter colorFilter) {
          // Do nothing
      }
  
      @Override
      public int getOpacity() {
          return PixelFormat.TRANSLUCENT;
      }
  
      private ObjectAnimator cancelAnimator(ObjectAnimator animator) {
          if (animator != null) {
              animator.cancel();
          }
          return null;
      }
  }
  