Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0917f939 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Raster and badge directshare with IconFactory"

parents 6798ab9e 9c4ae502
Loading
Loading
Loading
Loading
+38 −37
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.metrics.LogMaker;
@@ -1465,14 +1466,6 @@ public class ChooserActivity extends ResolverActivity {
            return null;
        }

        public Drawable getBadgeIcon() {
            return null;
        }

        public CharSequence getBadgeContentDescription() {
            return null;
        }

        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
            return null;
        }
@@ -1561,18 +1554,15 @@ public class ChooserActivity extends ResolverActivity {
         */
        // TODO(121287224): Refactor code to apply the suggestion above
        private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
            Drawable directShareIcon = null;

            // First get the target drawable and associated activity info
            final Icon icon = target.getIcon();
            if (icon != null) {
                return icon.loadDrawable(ChooserActivity.this);
            }
            if (!USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
                return null;
            }

                directShareIcon = icon.loadDrawable(ChooserActivity.this);
            } else if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
                Bundle extras = target.getIntentExtras();
            if (extras == null || !extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
                return null;
            }
                if (extras != null && extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
                    CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
                    LauncherApps launcherApps = (LauncherApps) getSystemService(
                            Context.LAUNCHER_APPS_SERVICE);
@@ -1582,10 +1572,31 @@ public class ChooserActivity extends ResolverActivity {
                    q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
                    final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
                    if (shortcuts != null && shortcuts.size() > 0) {
                return launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
                        directShareIcon = launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
                    }
                }
            }

            return null;
            if (directShareIcon == null) return null;

            ActivityInfo info = null;
            try {
                info = mPm.getActivityInfo(target.getComponentName(), 0);
            } catch (NameNotFoundException error) {
                Log.e(TAG, "Could not find activity associated with ChooserTarget");
            }

            if (info == null) return null;

            // Now fetch app icon and raster with no badging even in work profile
            Bitmap appIcon = (new ActivityInfoPresentationGetter(info)).getIconBitmap();

            // Raster target drawable with appIcon as a badge
            SimpleIconFactory sif = SimpleIconFactory.obtain(ChooserActivity.this);
            Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
            sif.recycle();

            return new BitmapDrawable(getResources(), directShareBadgedIcon);
        }

        public float getModifiedScore() {
@@ -1683,16 +1694,6 @@ public class ChooserActivity extends ResolverActivity {
            return mDisplayIcon;
        }

        @Override
        public Drawable getBadgeIcon() {
            return mBadgeIcon;
        }

        @Override
        public CharSequence getBadgeContentDescription() {
            return mBadgeContentDescription;
        }

        public ChooserTarget getChooserTarget() {
            return mChooserTarget;
        }
+125 −95
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -133,8 +133,6 @@ public class ResolverActivity extends Activity {
    /** See {@link #setRetainInOnStop}. */
    private boolean mRetainInOnStop;

    SimpleIconFactory mSimpleIconFactory;

    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
        @Override public void onSomePackagesChanged() {
            mAdapter.handlePackagesChanged();
@@ -311,11 +309,6 @@ public class ResolverActivity extends Activity {
        // as to mitigate Intent Capturing vulnerability
        mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;

        final int iconSize = getResources().getDimensionPixelSize(R.dimen.resolver_icon_size);
        final int badgeSize = getResources().getDimensionPixelSize(R.dimen.resolver_badge_size);
        mSimpleIconFactory = new SimpleIconFactory(this, mIconDpi, iconSize, badgeSize);
        mSimpleIconFactory.setWrapperBackgroundColor(Color.WHITE);

        if (configureContentView(mIntents, initialIntents, rList)) {
            return;
        }
@@ -500,64 +493,150 @@ public class ResolverActivity extends Activity {
        }
    }

    @Nullable
    Drawable getIcon(Resources res, int resId) {
        Drawable result;
        try {
            result = res.getDrawableForDensity(resId, mIconDpi);
        } catch (Resources.NotFoundException e) {
            result = null;
        }

        return result;
    }

    /**
     * Loads the icon for the provided ResolveInfo. Defaults to using the application icon over
     * Loads the icon for the provided ApplicationInfo. Defaults to using the application icon over
     * any IntentFilter or Activity icon to increase user understanding, with an exception for
     * applications that hold the right permission. Always attempts to use icon resources over
     * PackageManager loading mechanisms so badging can be done by iconloader.
     */
    Drawable loadIconForResolveInfo(ResolveInfo ri) {
        Drawable dr = null;
    private abstract class TargetPresentationGetter {
        @Nullable abstract Drawable getIconSubstitute();
        @Nullable abstract String getAppSubLabel();

        // Allow for app icon override given the right permission
        if (PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
        private final ApplicationInfo mAi;
        private final boolean mHasSubstitutePermission;

        TargetPresentationGetter(ApplicationInfo ai) {
            mAi = ai;
            mHasSubstitutePermission = PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
                    android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
                ri.activityInfo.applicationInfo.packageName)) {
                    mAi.packageName);
        }

        Drawable getIcon() {
            return new BitmapDrawable(getResources(), getIconBitmap());
        }

        Bitmap getIconBitmap() {
            Drawable dr = null;
            if (mHasSubstitutePermission) {
                dr = getIconSubstitute();
            }

            if (dr == null) {
                try {
                if (ri.resolvePackageName != null && ri.icon != 0) {
                    dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
                    if (mAi.icon != 0) {
                        dr = loadIconFromResource(mPm.getResourcesForApplication(mAi), mAi.icon);
                    }
                } catch (NameNotFoundException ignore) {
                }
            }

            // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
            if (dr == null) {
                    final int iconRes = ri.getIconResource();
                    if (iconRes != 0) {
                        dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName),
                                iconRes);
                dr = mAi.loadIcon(mPm);
            }

            SimpleIconFactory sif = SimpleIconFactory.obtain(ResolverActivity.this);
            Bitmap icon = sif.createUserBadgedIconBitmap(dr, Process.myUserHandle());
            sif.recycle();

            return icon;
        }

        String getLabel() {
            String label = null;
            // Apps with the substitute permission will always show the sublabel as their label
            if (mHasSubstitutePermission) {
                label = getAppSubLabel();
            }

            if (label == null) {
                label = (String) mAi.loadLabel(mPm);
            }

            return label;
        }

        String getSubLabel() {
            // Apps with the substitute permission will never have a sublabel
            if (mHasSubstitutePermission) return null;
            return getAppSubLabel();
        }

        @Nullable
        protected Drawable loadIconFromResource(Resources res, int resId) {
            return res.getDrawableForDensity(resId, mIconDpi);
        }

    }

    protected class ResolveInfoPresentationGetter extends TargetPresentationGetter {

        private final ResolveInfo mRi;

        ResolveInfoPresentationGetter(ResolveInfo ri) {
            super(ri.activityInfo.applicationInfo);
            mRi = ri;
        }

        @Override
        Drawable getIconSubstitute() {
            Drawable dr = null;
            try {
                // Do not use ResolveInfo#getIconResource() as it defaults to the app
                if (mRi.resolvePackageName != null && mRi.icon != 0) {
                    dr = loadIconFromResource(
                            mPm.getResourcesForApplication(mRi.resolvePackageName), mRi.icon);
                }
            } catch (NameNotFoundException e) {
                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
                        + "couldn't find resources for package", e);
            }

            return dr;
        }

        // Use app icons for better user association
        if (dr == null) {
        @Override
        String getAppSubLabel() {
            return (String) mRi.loadLabel(mPm);
        }
    }

    protected class ActivityInfoPresentationGetter extends TargetPresentationGetter {
        private final ActivityInfo mActivityInfo;
        protected ActivityInfoPresentationGetter(ActivityInfo activityInfo) {
            super(activityInfo.applicationInfo);
            mActivityInfo = activityInfo;
        }

        @Override
        Drawable getIconSubstitute() {
            Drawable dr = null;
            try {
                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.applicationInfo),
                        ri.activityInfo.applicationInfo.icon);
            } catch (NameNotFoundException ignore) {
                // Do not use ActivityInfo#getIconResource() as it defaults to the app
                if (mActivityInfo.icon != 0) {
                    dr = loadIconFromResource(
                            mPm.getResourcesForApplication(mActivityInfo.applicationInfo),
                            mActivityInfo.icon);
                }
            } catch (NameNotFoundException e) {
                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
                        + "couldn't find resources for package", e);
            }

        // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
        if (dr == null) {
            dr = ri.activityInfo.applicationInfo.loadIcon(mPm);
            return dr;
        }

        @Override
        String getAppSubLabel() {
            return (String) mActivityInfo.loadLabel(mPm);
        }
    }

        return new BitmapDrawable(this.getResources(),
                mSimpleIconFactory.createUserBadgedIconBitmap(dr, Process.myUserHandle()));
    Drawable loadIconForResolveInfo(ResolveInfo ri) {
        return (new ResolveInfoPresentationGetter(ri)).getIcon();
    }

    @Override
@@ -1250,33 +1329,6 @@ public class ResolverActivity extends Activity {
            return mDisplayIcon;
        }

        public Drawable getBadgeIcon() {
            // We only expose a badge if we have extended info.
            // The badge is a higher-priority disambiguation signal
            // but we don't need one if we wouldn't show extended info at all.
            if (TextUtils.isEmpty(getExtendedInfo())) {
                return null;
            }

            if (mBadge == null && mResolveInfo != null && mResolveInfo.activityInfo != null
                    && mResolveInfo.activityInfo.applicationInfo != null) {
                if (mResolveInfo.activityInfo.icon == 0 || mResolveInfo.activityInfo.icon
                        == mResolveInfo.activityInfo.applicationInfo.icon) {
                    // Badging an icon with exactly the same icon is silly.
                    // If the activityInfo icon resid is 0 it will fall back
                    // to the application's icon, making it a match.
                    return null;
                }
                mBadge = mResolveInfo.activityInfo.applicationInfo.loadIcon(mPm);
            }
            return mBadge;
        }

        @Override
        public CharSequence getBadgeContentDescription() {
            return null;
        }

        @Override
        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
            return new DisplayResolveInfo(this, fillInIntent, flags);
@@ -1413,20 +1465,10 @@ public class ResolverActivity extends Activity {
        CharSequence getExtendedInfo();

        /**
         * @return The drawable that should be used to represent this target
         * @return The drawable that should be used to represent this target including badge
         */
        Drawable getDisplayIcon();

        /**
         * @return The (small) icon to badge the target with
         */
        Drawable getBadgeIcon();

        /**
         * @return The content description for the badge icon
         */
        CharSequence getBadgeContentDescription();

        /**
         * Clone this target with the given fill-in information.
         */
@@ -1963,16 +2005,6 @@ public class ResolverActivity extends Activity {
                new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
            }
            holder.icon.setImageDrawable(info.getDisplayIcon());
            if (holder.badge != null) {
                final Drawable badge = info.getBadgeIcon();
                if (badge != null) {
                    holder.badge.setImageDrawable(badge);
                    holder.badge.setContentDescription(info.getBadgeContentDescription());
                    holder.badge.setVisibility(View.VISIBLE);
                } else {
                    holder.badge.setVisibility(View.GONE);
                }
            }
        }
    }

@@ -2027,13 +2059,11 @@ public class ResolverActivity extends Activity {
        public TextView text;
        public TextView text2;
        public ImageView icon;
        public ImageView badge;

        public ViewHolder(View view) {
            text = (TextView) view.findViewById(com.android.internal.R.id.text1);
            text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
            icon = (ImageView) view.findViewById(R.id.icon);
            badge = (ImageView) view.findViewById(R.id.target_badge);
        }
    }

+43 −2
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

package com.android.internal.app;

import static android.content.Context.ACTIVITY_SERVICE;
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -42,6 +44,7 @@ import android.graphics.drawable.DrawableWrapper;
import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Pools.SynchronizedPool;

import com.android.internal.R;

@@ -58,6 +61,9 @@ import java.nio.ByteBuffer;
@Deprecated
public class SimpleIconFactory {

    private static final SynchronizedPool<SimpleIconFactory> sPool =
            new SynchronizedPool<>(Runtime.getRuntime().availableProcessors());

    private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
    private static final float BLUR_FACTOR = 0.5f / 48;

@@ -73,11 +79,46 @@ public class SimpleIconFactory {
    private Drawable mWrapperIcon;
    private final Rect mOldBounds = new Rect();

    /**
     * Obtain a SimpleIconFactory from a pool objects.
     *
     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
     */
    @Deprecated
    public static SimpleIconFactory obtain(Context ctx) {
        SimpleIconFactory instance = sPool.acquire();
        if (instance == null) {
            final ActivityManager am = (ActivityManager) ctx.getSystemService(ACTIVITY_SERVICE);
            final int iconDpi = (am == null) ? 0 : am.getLauncherLargeIconDensity();

            final Resources r = ctx.getResources();
            final int iconSize = r.getDimensionPixelSize(R.dimen.resolver_icon_size);
            final int badgeSize = r.getDimensionPixelSize(R.dimen.resolver_badge_size);

            instance = new SimpleIconFactory(ctx, iconDpi, iconSize, badgeSize);
            instance.setWrapperBackgroundColor(Color.WHITE);
        }

        return instance;
    }

    /**
     * Recycles the SimpleIconFactory so others may use it.
     *
     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
     */
    @Deprecated
    public void recycle() {
        // Return to default background color
        setWrapperBackgroundColor(Color.WHITE);
        sPool.release(this);
    }

    /**
     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
     */
    @Deprecated
    SimpleIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
    private SimpleIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
            int badgeBitmapSize) {
        mContext = context.getApplicationContext();
        mPm = mContext.getPackageManager();
@@ -170,7 +211,7 @@ public class SimpleIconFactory {
     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
     */
    @Deprecated
    public Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
    Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
        // Flatten the passed in icon
        float [] scale = new float[1];

+7 −16
Original line number Diff line number Diff line
@@ -27,22 +27,13 @@
              android:focusable="true"
              android:background="?attr/selectableItemBackgroundBorderless">

    <FrameLayout android:layout_width="wrap_content"
                 android:layout_height="wrap_content">
    <ImageView android:id="@+id/icon"
                   android:layout_width="48dp"
                   android:layout_height="48dp"
               android:layout_width="@dimen/resolver_icon_size"
               android:layout_height="@dimen/resolver_icon_size"
               android:layout_marginLeft="3dp"
               android:layout_marginRight="3dp"
               android:layout_marginBottom="3dp"
               android:scaleType="fitCenter" />
        <ImageView android:id="@+id/target_badge"
                   android:layout_width="16dp"
                   android:layout_height="16dp"
                   android:layout_gravity="end|bottom"
                   android:visibility="gone"
                   android:scaleType="fitCenter" />
    </FrameLayout>

    <!-- Activity name -->
    <TextView android:id="@android:id/text1"
+0 −1
Original line number Diff line number Diff line
@@ -2779,7 +2779,6 @@

  <java-symbol type="layout" name="chooser_row" />
  <java-symbol type="layout" name="chooser_row_direct_share" />
  <java-symbol type="id" name="target_badge" />
  <java-symbol type="bool" name="config_supportDoubleTapWake" />
  <java-symbol type="drawable" name="ic_perm_device_info" />
  <java-symbol type="string" name="config_radio_access_family" />