content: /*
   * Copyright (C) 2016 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.icons;
  
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.ShortcutInfo;
  import android.graphics.Bitmap;
  import android.graphics.drawable.Drawable;
  import android.os.Process;
  
  import androidx.annotation.Nullable;
  
  import com.android.launcher3.AppInfo;
  import com.android.launcher3.FastBitmapDrawable;
  import com.android.launcher3.InvariantDeviceProfile;
  import com.android.launcher3.ItemInfoWithIcon;
  import com.android.launcher3.LauncherAppState;
  import com.android.launcher3.R;
  import com.android.launcher3.graphics.IconShape;
  import com.android.launcher3.model.PackageItemInfo;
  import com.android.launcher3.shortcuts.DeepShortcutManager;
  import com.android.launcher3.util.Themes;
  
  import java.util.function.Supplier;
  
  /**
   * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
   * that are threadsafe.
   */
  public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
  
      private static final String EXTRA_BADGEPKG = "badge_package";
  
      private static final Object sPoolSync = new Object();
      private static LauncherIcons sPool;
      private static int sPoolId = 0;
  
      public static LauncherIcons obtain(Context context) {
          return obtain(context, IconShape.getShape().enableShapeDetection());
      }
  
      /**
       * Return a new Message instance from the global pool. Allows us to
       * avoid allocating new objects in many cases.
       */
      public static LauncherIcons obtain(Context context, boolean shapeDetection) {
          int poolId;
          synchronized (sPoolSync) {
              if (sPool != null) {
                  LauncherIcons m = sPool;
                  sPool = m.next;
                  m.next = null;
                  return m;
              }
              poolId = sPoolId;
          }
  
          InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
          return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId,
                  shapeDetection);
      }
  
      public static void clearPool() {
          synchronized (sPoolSync) {
              sPool = null;
              sPoolId++;
          }
      }
  
      private final int mPoolId;
  
      private LauncherIcons next;
  
      private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId,
              boolean shapeDetection) {
          super(context, fillResIconDpi, iconBitmapSize, shapeDetection);
          mPoolId = poolId;
      }
  
      /**
       * Recycles a LauncherIcons that may be in-use.
       */
      public void recycle() {
          synchronized (sPoolSync) {
              if (sPoolId != mPoolId) {
                  return;
              }
              // Clear any temporary state variables
              clear();
  
              next = sPool;
              sPool = this;
          }
      }
  
      @Override
      public void close() {
          recycle();
      }
  
      // below methods should also migrate to BaseIconFactory
  
      public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) {
          return createShortcutIcon(shortcutInfo, true /* badged */);
      }
  
      public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged) {
          return createShortcutIcon(shortcutInfo, badged, null);
      }
  
      public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo,
              boolean badged, @Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
          Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
                  .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
          IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
  
          final Bitmap unbadgedBitmap;
          if (unbadgedDrawable != null) {
              unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
          } else {
              if (fallbackIconProvider != null) {
                  // Fallback icons are already badged and with appropriate shadow
                  ItemInfoWithIcon fullIcon = fallbackIconProvider.get();
                  if (fullIcon != null && fullIcon.iconBitmap != null) {
                      BitmapInfo result = new BitmapInfo();
                      result.icon = fullIcon.iconBitmap;
                      result.color = fullIcon.iconColor;
                      return result;
                  }
              }
              unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
          }
  
          BitmapInfo result = new BitmapInfo();
          if (!badged) {
              result.color = Themes.getColorAccent(mContext);
              result.icon = unbadgedBitmap;
              return result;
          }
  
          final Bitmap unbadgedfinal = unbadgedBitmap;
          final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
  
          result.color = badge.iconColor;
          result.icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
              getShadowGenerator().recreateIcon(unbadgedfinal, c);
              badgeWithDrawable(c, new FastBitmapDrawable(badge));
          });
          return result;
      }
  
      public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfo shortcutInfo, IconCache cache) {
          ComponentName cn = shortcutInfo.getActivity();
          String badgePkg = getBadgePackage(shortcutInfo);
          boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage());
          if (cn != null && !hasBadgePkgSet) {
              // Get the app info for the source activity.
              AppInfo appInfo = new AppInfo();
              appInfo.user = shortcutInfo.getUserHandle();
              appInfo.componentName = cn;
              appInfo.intent = new Intent(Intent.ACTION_MAIN)
                      .addCategory(Intent.CATEGORY_LAUNCHER)
                      .setComponent(cn);
              cache.getTitleAndIcon(appInfo, false);
              return appInfo;
          } else {
              PackageItemInfo pkgInfo = new PackageItemInfo(badgePkg);
              cache.getTitleAndIconForApp(pkgInfo, false);
              return pkgInfo;
          }
      }
  
      private String getBadgePackage(ShortcutInfo si) {
          String whitelistedPkg = mContext.getString(R.string.shortcutinfo_badgepkg_whitelist);
          if (whitelistedPkg.equals(si.getPackage())
                  && si.getExtras() != null
                  && si.getExtras().containsKey(EXTRA_BADGEPKG)) {
              return si.getExtras().getString(EXTRA_BADGEPKG);
          }
          return si.getPackage();
      }
  }
  