package com.lody.virtual.server.notification;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import com.lody.virtual.R;
import com.lody.virtual.helper.utils.Reflect;
import com.lody.virtual.helper.utils.VLog;
import java.util.ArrayList;
import java.util.HashMap;
/* package */ class RemoteViewsFixer {
private static final String TAG = NotificationCompat.TAG;
private final WidthCompat mWidthCompat;
private int notification_min_height, notification_max_height, notification_mid_height;
private int notification_panel_width;
private int notification_side_padding;
private int notification_padding;
private final HashMap<String, Bitmap> mImages = new HashMap<>();
private NotificationCompat mNotificationCompat;
RemoteViewsFixer(NotificationCompat notificationCompat) {
mWidthCompat = new WidthCompat();
mNotificationCompat = notificationCompat;
}
View toView(final Context context, RemoteViews remoteViews, boolean isBig, boolean systemId) {
View mCache = null;
try {
mCache = createView(context, remoteViews, isBig, systemId);
} catch (Throwable throwable) {
VLog.w(TAG, "toView 1", throwable);
try {
mCache = LayoutInflater.from(context).inflate(remoteViews.getLayoutId(), null);
} catch (Throwable e) {
VLog.w(TAG, "toView 2", e);
}
}
return mCache;
}
Bitmap createBitmap(View mCache) {
if (mCache == null) {
return null;
}
mCache.setDrawingCacheEnabled(true);
mCache.buildDrawingCache();
return mCache.getDrawingCache();
}
private View apply(Context context, RemoteViews remoteViews) {
View view = null;
try {
view = LayoutInflater.from(context).inflate(remoteViews.getLayoutId(), null, false);
try {
Reflect.on(view).call("setTagInternal", Reflect.on("com.android.internal.R$id").get("widget_frame"), remoteViews.getLayoutId());
} catch (Exception e2) {
VLog.w(TAG, "setTagInternal", e2);
}
} catch (Exception e) {
VLog.w(TAG, "inflate", e);
}
if (view != null) {
ArrayList<Object> mActions = Reflect.on(remoteViews).get("mActions");
if (mActions != null) {
VLog.d(TAG, "apply actions:"+mActions.size());
for (Object action : mActions) {
try {
Reflect.on(action).call("apply", view, null, null);
} catch (Exception e) {
VLog.w(TAG, "apply action", e);
}
}
}
} else {
VLog.e(TAG, "create views");
}
return view;
}
private View createView(final Context context, RemoteViews remoteViews, boolean isBig, boolean systemId) {
if (remoteViews == null)
return null;
Context base = mNotificationCompat.getHostContext();
init(base);
VLog.v(TAG, "createView:big=" + isBig + ",system=" + systemId);
int height = isBig ? notification_max_height : notification_min_height;
int width = mWidthCompat.getNotificationWidth(base, notification_panel_width, height,
notification_side_padding);
VLog.v(TAG, "createView:getNotificationWidth=" + width);
ViewGroup frameLayout = new FrameLayout(context);
VLog.v(TAG, "createView:apply");
View view1 = apply(context, remoteViews);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER_VERTICAL;
frameLayout.addView(view1, params);
if (view1 instanceof ViewGroup) {
VLog.v(TAG, "createView:fixTextView");
fixTextView((ViewGroup) view1);
}
int mode;
//TODO need adaptation
if (systemId) {
mode = View.MeasureSpec.EXACTLY;
} else {
if (isBig) {
mode = View.MeasureSpec.AT_MOST;
} else {
mode = View.MeasureSpec.EXACTLY;
}
}
VLog.v(TAG, "createView:layout");
View mCache = frameLayout;
mCache.layout(0, 0, width, height);
mCache.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, mode));
mCache.layout(0, 0, width, mCache.getMeasuredHeight());
VLog.v(TAG, "notification:systemId=" + systemId + ",max=%d/%d, szie=%d/%d", width, height,
mCache.getMeasuredWidth(), mCache.getMeasuredHeight());
return mCache;
}
private void fixTextView(ViewGroup viewGroup) {
int count = viewGroup.getChildCount();
for (int i = 0; i < count; i++) {
View v = viewGroup.getChildAt(i);
if (v instanceof TextView) {
TextView tv = (TextView) v;
if (isSingleLine(tv)) {
tv.setSingleLine(false);
tv.setMaxLines(1);
}
} else if (v instanceof ViewGroup) {
fixTextView((ViewGroup) v);
}
}
}
private boolean isSingleLine(TextView textView) {
boolean singleLine;
try {
singleLine = Reflect.on(textView).get("mSingleLine");
} catch (Exception e) {
singleLine = (textView.getInputType() & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
}
return singleLine;
}
public RemoteViews makeRemoteViews(String key, Context pluginContext, RemoteViews contentView, boolean isBig, boolean click) {
if (contentView == null) {
return null;
}
final boolean systemId = false;
final PendIntentCompat pendIntentCompat = new PendIntentCompat(contentView);
final int layoutId;
if (!click || pendIntentCompat.findPendIntents() <= 0) {
layoutId = R.layout.custom_notification_lite;
} else {
layoutId = R.layout.custom_notification;
}
VLog.v(TAG, "createviews id = " + layoutId);
//make a remoteViews
RemoteViews remoteViews = new RemoteViews(mNotificationCompat.getHostContext().getPackageName(), layoutId);
VLog.v(TAG, "remoteViews to view");
View cache = toView(pluginContext, contentView, isBig, systemId);
// remoteViews to bitmap
VLog.v(TAG, "start createBitmap");
final Bitmap bmp = createBitmap(cache);
if (bmp == null) {
VLog.e(TAG, "bmp is null,contentView=" + contentView);
// return null; //ignore notification
} else {
VLog.v(TAG, "bmp w=" + bmp.getWidth() + ",h=" + bmp.getHeight());
}
Bitmap old;
synchronized (mImages) {
old = mImages.get(key);
}
if (old != null && !old.isRecycled()) {
VLog.v(TAG, "recycle " + key);
old.recycle();
}
remoteViews.setImageViewBitmap(R.id.im_main, bmp);
VLog.v(TAG, "createview " + key);
synchronized (mImages) {
mImages.put(key, bmp);
}
//notification's click
if (click) {
if (layoutId == R.layout.custom_notification) {
VLog.v(TAG, "start setPendIntent");
try {
pendIntentCompat.setPendIntent(remoteViews,
toView(mNotificationCompat.getHostContext(), remoteViews, isBig, systemId),
cache);
} catch (Exception e) {
VLog.e(TAG, "setPendIntent error", e);
}
}
}
return remoteViews;
}
private boolean init = false;
private void init(Context context) {
if (init) return;
init = true;
if (notification_panel_width == 0) {
Context systemUi = null;
try {
systemUi = context.createPackageContext(NotificationCompat.SYSTEM_UI_PKG, Context.CONTEXT_IGNORE_SECURITY);
} catch (PackageManager.NameNotFoundException e) {
}
if (Build.VERSION.SDK_INT <= 19) {
notification_side_padding = 0;
} else {
notification_side_padding = getDimem(context, systemUi, "notification_side_padding",
R.dimen.notification_side_padding);
}
notification_panel_width = getDimem(context, systemUi, "notification_panel_width",
R.dimen.notification_panel_width);
if (notification_panel_width <= 0) {
notification_panel_width = context.getResources().getDisplayMetrics().widthPixels;
}
notification_min_height = getDimem(context, systemUi, "notification_min_height",
R.dimen.notification_min_height);
// getDimem(context, systemUi, "notification_row_min_height", 0);
// if (notification_min_height == 0) {
// notification_min_height =
// }
notification_max_height = getDimem(context, systemUi, "notification_max_height",
R.dimen.notification_max_height);
notification_mid_height = getDimem(context, systemUi, "notification_mid_height",
R.dimen.notification_mid_height);
notification_padding = getDimem(context, systemUi, "notification_padding", R.dimen.notification_padding);
// notification_collapse_second_card_padding
}
}
private int getDimem(Context context, Context sysContext, String name, int defId) {
if (sysContext != null) {
int id = sysContext.getResources().getIdentifier(name, "dimen", NotificationCompat.SYSTEM_UI_PKG);
if (id != 0) {
try {
return Math.round(sysContext.getResources().getDimension(id));
} catch (Exception e) {
}
}
}
// VLog.w(TAG, "use my dimen:" + name);
return defId == 0 ? 0 : Math.round(context.getResources().getDimension(defId));
}
}