package com.lody.virtual.server.notification; import android.annotation.TargetApi; import android.app.Notification; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.widget.RemoteViews; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.helper.utils.Reflect; import com.lody.virtual.helper.utils.VLog; import java.util.ArrayList; import java.util.List; import mirror.com.android.internal.R_Hide; /* package */ class NotificationFixer { private static final String TAG = NotificationCompat.TAG; private NotificationCompat mNotificationCompat; NotificationFixer(NotificationCompat notificationCompat) { this.mNotificationCompat = notificationCompat; } private static void fixNotificationIcon(Context context, Notification notification, Notification.Builder builder) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { //noinspection deprecation builder.setSmallIcon(notification.icon); //noinspection deprecation builder.setLargeIcon(notification.largeIcon); } else { Icon icon = notification.getSmallIcon(); if (icon != null) { Bitmap bitmap = drawableToBitMap(icon.loadDrawable(context)); if (bitmap != null) { Icon newIcon = Icon.createWithBitmap(bitmap); builder.setSmallIcon(newIcon); } } Icon largeIcon = notification.getLargeIcon(); if (largeIcon != null) { Bitmap bitmap = drawableToBitMap(largeIcon.loadDrawable(context)); if (bitmap != null) { Icon newIcon = Icon.createWithBitmap(bitmap); builder.setLargeIcon(newIcon); } } } } private static Bitmap drawableToBitMap(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { BitmapDrawable bitmapDrawable = ((BitmapDrawable) drawable); return bitmapDrawable.getBitmap(); } else { Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; } } void fixIcon(Icon icon, Context appContext, boolean installed) { if (icon == null) { return; } int type = mirror.android.graphics.drawable.Icon.mType.get(icon); if (type == mirror.android.graphics.drawable.Icon.TYPE_RESOURCE) { if (installed) { mirror.android.graphics.drawable.Icon.mObj1.set(icon, appContext.getResources()); mirror.android.graphics.drawable.Icon.mString1.set(icon, appContext.getPackageName()); } else { Drawable drawable = icon.loadDrawable(appContext); Bitmap bitmap = drawableToBitMap(drawable); mirror.android.graphics.drawable.Icon.mObj1.set(icon, bitmap); mirror.android.graphics.drawable.Icon.mString1.set(icon, null); mirror.android.graphics.drawable.Icon.mType.set(icon, mirror.android.graphics.drawable.Icon.TYPE_BITMAP); } } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) void fixNotificationRemoteViews(Context pluginContext, Notification notification) { Notification.Builder rebuild = null; try { rebuild = Reflect.on(Notification.Builder.class).create(pluginContext, notification).get(); } catch (Exception e) { // ignore } if (rebuild != null) { Notification renotification = rebuild.build(); if (notification.tickerView == null) { notification.tickerView = renotification.tickerView; } if (notification.contentView == null) { notification.contentView = renotification.contentView; } if (notification.bigContentView == null) { notification.bigContentView = renotification.bigContentView; } if (notification.headsUpContentView == null) { notification.headsUpContentView = renotification.headsUpContentView; } } } boolean fixRemoteViewActions(Context appContext, boolean installed, final RemoteViews remoteViews) { boolean hasIcon = false; if (remoteViews != null) { int systemIconViewId = R_Hide.id.icon.get(); List<BitmapReflectionAction> mNew = new ArrayList<>(); ArrayList<Object> mActions = Reflect.on(remoteViews).get("mActions"); if (mActions != null) { int count = mActions.size(); for (int i = count - 1; i >= 0; i--) { Object action = mActions.get(i); if (action == null) { continue; } //TextViewDrawableAction //setImageURI //setLabelFor if (action.getClass().getSimpleName().endsWith("TextViewDrawableAction")) { mActions.remove(action); continue; } if (ReflectionActionCompat.isInstance(action) || (action.getClass().getSimpleName().endsWith("ReflectionAction"))) { int viewId = Reflect.on(action).get("viewId"); String methodName = Reflect.on(action).get("methodName"); int type = Reflect.on(action).get("type"); Object value = Reflect.on(action).get("value"); if (!hasIcon) { hasIcon = viewId == systemIconViewId; if (hasIcon) { if (type == ReflectionActionCompat.INT && (int) value == 0) { hasIcon = false; } if (hasIcon) { VLog.v(TAG, "find icon " + methodName + " type=" + type + ", value=" + value); } } } if (methodName.equals("setImageResource")) { //setImageBitmap mNew.add(new BitmapReflectionAction(viewId, "setImageBitmap", drawableToBitMap(appContext.getResources().getDrawable((int) value)))); mActions.remove(action); } else if (methodName.equals("setText") && type == ReflectionActionCompat.INT) { //setText string Reflect.on(action).set("type", ReflectionActionCompat.STRING); Reflect.on(action).set("value", appContext.getResources().getString((int) value)); } else if (methodName.equals("setLabelFor")) { //TODO remove mActions.remove(action); } else if (methodName.equals("setBackgroundResource")) { //TODO remove mActions.remove(action); } else if (methodName.equals("setImageURI")) { Uri uri = (Uri) value; if (!uri.getScheme().startsWith("http")) { mActions.remove(action); } } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (value instanceof Icon) { Icon icon = (Icon) value; fixIcon(icon, appContext, installed); } } } } } for (BitmapReflectionAction action : mNew) { remoteViews.setBitmap(action.viewId, action.methodName, action.bitmap); } } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { mirror.android.widget.RemoteViews.mPackage.set(remoteViews, VirtualCore.get().getHostPkg()); } } return hasIcon; } void fixIconImage(Resources resources, RemoteViews remoteViews, boolean hasIconBitmap, Notification notification) { if (remoteViews == null) return; if (!mNotificationCompat.isSystemLayout(remoteViews)) { return; } try { //noinspection deprecation int id = R_Hide.id.icon.get(); //only fake small icon if (!hasIconBitmap && notification.largeIcon == null) { Drawable drawable = resources.getDrawable(notification.icon); drawable.setLevel(notification.iconLevel); Bitmap bitmap = drawableToBitMap(drawable); remoteViews.setImageViewBitmap(id, bitmap); } if (Build.VERSION.SDK_INT >= 21) { remoteViews.setInt(id, "setBackgroundColor", Color.TRANSPARENT); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { remoteViews.setViewPadding(id, 0, 0, 0, 0); } } catch (Exception e) { e.printStackTrace(); } } private static class BitmapReflectionAction { int viewId; String methodName; Bitmap bitmap; BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) { this.viewId = viewId; this.methodName = methodName; this.bitmap = bitmap; } } }