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

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

Merge "Simplifying disabled widget view genration" into sc-dev

parents 0920fbb4 4671a2d5
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.internal.widget;

import android.annotation.Nullable;
import android.content.Context;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RemoteViews;

/**
 * ImageView which applies a saturation image filter, used by AppWidgets to represent disabled icon
 */
@RemoteViews.RemoteView
public class DisableImageView extends ImageView {

    public DisableImageView(Context context) {
        this(context, null, 0, 0);
    }

    public DisableImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0, 0);
    }

    public DisableImageView(Context context, @Nullable AttributeSet attrs,
            int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public DisableImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        // Apply the disabled filter
        ColorMatrix brightnessMatrix = new ColorMatrix();
        float brightnessF = 0.5f;
        int brightnessI = (int) (255 * brightnessF);
        // Brightness: C-new = C-old*(1-amount) + amount
        float scale = 1f - brightnessF;
        float[] mat = brightnessMatrix.getArray();
        mat[0] = scale;
        mat[6] = scale;
        mat[12] = scale;
        mat[4] = brightnessI;
        mat[9] = brightnessI;
        mat[14] = brightnessI;

        ColorMatrix filterMatrix = new ColorMatrix();
        filterMatrix.setSaturation(0);
        filterMatrix.preConcat(brightnessMatrix);
        setColorFilter(new ColorMatrixColorFilter(filterMatrix));
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -22,7 +22,8 @@ Copyright (C) 2015 The Android Open Source Project
    android:importantForAccessibility="noHideDescendants"
    android:clickable="true">

    <ImageView android:id="@+id/work_widget_app_icon"
    <com.android.internal.widget.DisableImageView
        android:id="@+id/work_widget_app_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
+36 −76
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
@@ -66,9 +65,8 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -119,7 +117,6 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.widget.IRemoteViewsFactory;
import com.android.server.LocalServices;
import com.android.server.WidgetBackupProvider;
import com.android.server.policy.IconUtilities;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -253,8 +250,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    private boolean mSafeMode;
    private int mMaxWidgetBitmapMemory;

    private IconUtilities mIconUtilities;

    AppWidgetServiceImpl(Context context) {
        mContext = context;
    }
@@ -271,7 +266,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
        mBackupRestoreController = new BackupRestoreController();
        mSecurityPolicy = new SecurityPolicy();
        mIconUtilities = new IconUtilities(mContext);

        computeMaximumWidgetBitmapMemory();
        registerBroadcastReceiver();
@@ -578,44 +572,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        }
    }

    private Bitmap createMaskedWidgetBitmap(String providerPackage, int providerUserId) {
        final long identity = Binder.clearCallingIdentity();
        try {
            // Load the unbadged application icon and pass it to the widget to appear on
            // the masked view.
            Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
                    UserHandle.of(providerUserId));
            PackageManager pm = userContext.getPackageManager();
            Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm).mutate();
            // Create a bitmap of the icon which is what the widget's remoteview requires.
            icon.setColorFilter(mIconUtilities.getDisabledColorFilter());
            return mIconUtilities.createIconBitmap(icon);
        } catch (NameNotFoundException e) {
            Slog.e(TAG, "Fail to get application icon", e);
            // Provider package removed, no need to mask its views as its state will be
            // purged very soon.
            return null;
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    private RemoteViews createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge,
            PendingIntent onClickIntent) {
        RemoteViews views = new RemoteViews(mContext.getPackageName(),
                R.layout.work_widget_mask_view);
        if (icon != null) {
            views.setImageViewBitmap(R.id.work_widget_app_icon, icon);
        }
        if (!showBadge) {
            views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
        }
        if (onClickIntent != null) {
            views.setOnClickPendingIntent(R.id.work_widget_mask_frame, onClickIntent);
        }
        return views;
    }

    /**
     * Mask the target widget belonging to the specified provider, or all active widgets
     * of the provider if target widget == null.
@@ -625,59 +581,63 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        if (widgetCount == 0) {
            return;
        }
        final String providerPackage = provider.id.componentName.getPackageName();
        final int providerUserId = provider.getUserId();
        Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId);
        if (iconBitmap == null) {
            return;
        }
        final boolean showBadge;
        final Intent onClickIntent;
        RemoteViews views = new RemoteViews(mContext.getPackageName(),
                R.layout.work_widget_mask_view);
        ApplicationInfo appInfo = provider.info.providerInfo.applicationInfo;
        final int appUserId = provider.getUserId();
        boolean showBadge;

        final long identity = Binder.clearCallingIdentity();
        try {
            final Intent onClickIntent;

            if (provider.maskedBySuspendedPackage) {
                showBadge = mUserManager.hasBadge(providerUserId);
                showBadge = mUserManager.hasBadge(appUserId);
                final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
                        providerPackage, providerUserId);
                        appInfo.packageName, appUserId);
                if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
                    onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
                            providerUserId, true);
                            appUserId, true);
                } else {
                    final SuspendDialogInfo dialogInfo =
                            mPackageManagerInternal.getSuspendedDialogInfo(providerPackage,
                                    suspendingPackage, providerUserId);
                            mPackageManagerInternal.getSuspendedDialogInfo(
                                    appInfo.packageName, suspendingPackage, appUserId);
                    // onUnsuspend is null because we don't want to start any activity on
                    // unsuspending from a suspended widget.
                    onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
                            providerPackage, suspendingPackage, dialogInfo, null, null,
                            providerUserId);
                            appInfo.packageName, suspendingPackage, dialogInfo, null, null,
                            appUserId);
                }
            } else if (provider.maskedByQuietProfile) {
                showBadge = true;
                onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
                        providerUserId);
                onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
            } else /* provider.maskedByLockedProfile */ {
                showBadge = true;
                onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
                        providerUserId);
                onClickIntent = mKeyguardManager
                        .createConfirmDeviceCredentialIntent(null, null, appUserId);
                if (onClickIntent != null) {
                    onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK
                            | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    onClickIntent.setFlags(
                            FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                }
            }

            if (onClickIntent != null) {
                views.setOnClickPendingIntent(R.id.work_widget_mask_frame,
                        PendingIntent.getActivity(mContext, 0, onClickIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
            }

            Icon icon = appInfo.icon != 0
                    ? Icon.createWithResource(appInfo.packageName, appInfo.icon)
                    : Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
            views.setImageViewIcon(R.id.work_widget_app_icon, icon);
            if (!showBadge) {
                views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
            }

            for (int j = 0; j < widgetCount; j++) {
                Widget widget = provider.widgets.get(j);
                if (targetWidget != null && targetWidget != widget) continue;
                PendingIntent intent = null;
                if (onClickIntent != null) {
                    // Rare informational activity click is okay being
                    // immutable; the tradeoff is more security in exchange for
                    // losing bounds-based window animations
                    intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
                            onClickIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
                }
                RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
                if (widget.replaceWithMaskedViewsLocked(views)) {
                    scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
                }
+0 −151
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 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.server.policy;

import android.graphics.ColorFilter;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.TableMaskFilter;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.content.res.Resources;
import android.content.Context;

/**
 * Various utilities shared amongst the Launcher's classes.
 */
public final class IconUtilities {

    private int mIconWidth = -1;
    private int mIconHeight = -1;
    private int mIconTextureWidth = -1;
    private int mIconTextureHeight = -1;

    private final Rect mOldBounds = new Rect();
    private final Canvas mCanvas = new Canvas();
    private final DisplayMetrics mDisplayMetrics;

    private ColorFilter mDisabledColorFilter;

    public IconUtilities(Context context) {
        final Resources resources = context.getResources();
        DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics();
        final float density = metrics.density;
        final float blurPx = 5 * density;

        mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
        mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
                Paint.FILTER_BITMAP_FLAG));
    }

    /**
     * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
     * of two sized ARGB_8888 bitmap that can be used as a gl texture.
     */
    public Bitmap createIconBitmap(Drawable icon) {
        int width = mIconWidth;
        int height = mIconHeight;

        if (icon instanceof PaintDrawable) {
            PaintDrawable painter = (PaintDrawable) icon;
            painter.setIntrinsicWidth(width);
            painter.setIntrinsicHeight(height);
        } else if (icon instanceof BitmapDrawable) {
            // Ensure the bitmap has a density.
            BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
                bitmapDrawable.setTargetDensity(mDisplayMetrics);
            }
        }
        int sourceWidth = icon.getIntrinsicWidth();
        int sourceHeight = icon.getIntrinsicHeight();

        if (sourceWidth > 0 && sourceHeight > 0) {
            // There are intrinsic sizes.
            if (width < sourceWidth || height < sourceHeight) {
                // It's too big, scale it down.
                final float ratio = (float) sourceWidth / sourceHeight;
                if (sourceWidth > sourceHeight) {
                    height = (int) (width / ratio);
                } else if (sourceHeight > sourceWidth) {
                    width = (int) (height * ratio);
                }
            } else if (sourceWidth < width && sourceHeight < height) {
                // It's small, use the size they gave us.
                width = sourceWidth;
                height = sourceHeight;
            }
        }

        // no intrinsic size --> use default size
        int textureWidth = mIconTextureWidth;
        int textureHeight = mIconTextureHeight;

        final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                Bitmap.Config.ARGB_8888);
        final Canvas canvas = mCanvas;
        canvas.setBitmap(bitmap);

        final int left = (textureWidth-width) / 2;
        final int top = (textureHeight-height) / 2;

        mOldBounds.set(icon.getBounds());
        icon.setBounds(left, top, left+width, top+height);
        icon.draw(canvas);
        icon.setBounds(mOldBounds);

        return bitmap;
    }

    public ColorFilter getDisabledColorFilter() {
        if (mDisabledColorFilter != null) {
            return mDisabledColorFilter;
        }
        ColorMatrix brightnessMatrix = new ColorMatrix();
        float brightnessF = 0.5f;
        int brightnessI = (int) (255 * brightnessF);
        // Brightness: C-new = C-old*(1-amount) + amount
        float scale = 1f - brightnessF;
        float[] mat = brightnessMatrix.getArray();
        mat[0] = scale;
        mat[6] = scale;
        mat[12] = scale;
        mat[4] = brightnessI;
        mat[9] = brightnessI;
        mat[14] = brightnessI;

        ColorMatrix filterMatrix = new ColorMatrix();
        filterMatrix.setSaturation(0);
        filterMatrix.preConcat(brightnessMatrix);

        mDisabledColorFilter = new ColorMatrixColorFilter(filterMatrix);
        return mDisabledColorFilter;
    }
}
+4 −5
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ import android.net.Uri;
import android.os.Bundle;

import com.android.internal.R;
import com.android.server.policy.IconUtilities;
import com.android.internal.util.ImageUtils;

/** Displays an ongoing notification for a process displaying an alert window */
class AlertWindowNotification {
@@ -54,7 +54,6 @@ class AlertWindowNotification {
    private final NotificationManager mNotificationManager;
    private final String mPackageName;
    private boolean mPosted;
    private IconUtilities mIconUtilities;

    AlertWindowNotification(WindowManagerService service, String packageName) {
        mService = service;
@@ -63,7 +62,6 @@ class AlertWindowNotification {
                (NotificationManager) mService.mContext.getSystemService(NOTIFICATION_SERVICE);
        mNotificationTag = CHANNEL_PREFIX + mPackageName;
        mRequestCode = sNextRequestCode++;
        mIconUtilities = new IconUtilities(mService.mContext);
    }

    void post() {
@@ -126,8 +124,9 @@ class AlertWindowNotification {

        if (aInfo != null) {
            final Drawable drawable = pm.getApplicationIcon(aInfo);
            if (drawable != null) {
                final Bitmap bitmap = mIconUtilities.createIconBitmap(drawable);
            int size = context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
            final Bitmap bitmap = ImageUtils.buildScaledBitmap(drawable, size, size);
            if (bitmap != null) {
                builder.setLargeIcon(bitmap);
            }
        }