Merge "Simplifying disabled widget view genration" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1890877201
68
core/java/com/android/internal/widget/DisableImageView.java
Normal file
68
core/java/com/android/internal/widget/DisableImageView.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user