Files
MoGoEagleEye/app/src/main/java/com/mogo/launcher/lancet/ViewPressedStateLancet.java

578 lines
23 KiB
Java

package com.mogo.launcher.lancet;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import com.knightboost.lancet.api.Origin;
import com.knightboost.lancet.api.Scope;
import com.knightboost.lancet.api.annotations.Group;
import com.knightboost.lancet.api.annotations.ImplementedInterface;
import com.knightboost.lancet.api.annotations.Insert;
import com.knightboost.lancet.api.annotations.ReplaceInvoke;
import com.knightboost.lancet.api.annotations.TargetClass;
import com.knightboost.lancet.api.annotations.TargetMethod;
import com.knightboost.lancet.api.annotations.Weaver;
import com.mogo.launcher.R;
@Weaver
@Group("view_pressed_state")
public class ViewPressedStateLancet {
public static boolean isHasBackground(View view) {
if (view instanceof ImageView) {
ImageView image = (ImageView) view;
return image.getBackground() != null || image.getDrawable() != null;
}
if (view instanceof TextView) {
TextView text = (TextView) view;
return text.getBackground() != null;
}
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
View child = group.getChildAt(i);
if (isHasBackground(child)) {
return true;
}
}
}
return view.getBackground() != null;
}
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "setOnClickListener")
@ReplaceInvoke
public static void setOnClickListener(View view, View.OnClickListener listener) {
if (view == null) {
return;
}
if (listener == null) {
view.setOnClickListener(null);
return;
}
if (isHasBackground(view)) {
Object tag = view.getTag(R.id.click_pressed_attr_id);
checkSetBgIfNeed(null, view, tag == null ? null : (AttributeSet) tag, true);
} else if (view instanceof TextView) {
Object tag = view.getTag(R.id.click_pressed_attr_id);
checkSetBgIfNeed(null, (TextView) view, tag == null ? null : (AttributeSet) tag, true);
}
view.setOnClickListener(listener);
}
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "getBackground")
@ReplaceInvoke
public static Drawable getBackgroundDrawable(View view) {
Object tag = view.getTag(R.id.click_pressed_attr_replaced);
Drawable old = view.getBackground();
if (tag == null) {
return old;
}
return (Drawable) tag;
}
@TargetClass(value = "android.widget.ImageView", scope = Scope.ALL)
@TargetMethod(methodName = "getDrawable")
@ReplaceInvoke
public static Drawable getDrawable(ImageView view) {
Object tag = view.getTag(R.id.click_pressed_attr_replaced);
Drawable old = view.getDrawable();
if (tag == null) {
return old;
}
return (Drawable) tag;
}
@TargetClass(value = "android.widget.TextView", scope = Scope.ALL)
@TargetMethod(methodName = "getTextColors")
@ReplaceInvoke
public static ColorStateList getTextColors(TextView view) {
Object tag = view.getTag(R.id.click_pressed_attr_replaced_color);
ColorStateList old = view.getTextColors();
if (tag == null) {
return old;
}
return (ColorStateList) tag;
}
@TargetClass(value = "android.widget.CompoundButton", scope = Scope.ALL)
@TargetMethod(methodName = "setOnCheckedChangeListener")
@ReplaceInvoke
public static void setOnCheckedChangeListener(CompoundButton view, CompoundButton.OnCheckedChangeListener listener) {
if (view == null) {
return;
}
if (listener == null) {
view.setOnCheckedChangeListener(null);
return;
}
if (isHasBackground(view)) {
Object tag = view.getTag(R.id.click_pressed_attr_id);
checkSetBgIfNeed(null, view, tag == null ? null : (AttributeSet) tag, true);
}
view.setOnCheckedChangeListener(listener);
}
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "setOnLongClickListener")
@ReplaceInvoke
public static void setOnLongClickListener(View view, View.OnLongClickListener listener) {
if (view == null) {
return;
}
if (listener == null) {
view.setOnLongClickListener(null);
return;
}
if (isHasBackground(view)) {
Object tag = view.getTag(R.id.click_pressed_attr_id);
checkSetBgIfNeed(null, view, tag == null ? null : (AttributeSet) tag, true);
} else if (view instanceof TextView) {
Object tag = view.getTag(R.id.click_pressed_attr_id);
checkSetBgIfNeed(null, (TextView) view, tag == null ? null : (AttributeSet) tag, true);
}
view.setOnLongClickListener(listener);
}
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "setBackgroundDrawable")
@ReplaceInvoke
public static void setBackgroundDrawable(View view, Drawable drawable) {
if (view == null) {
return;
}
if (!view.isLongClickable() && !view.isClickable()) {
view.setBackground(drawable);
return;
}
float alpha = getAlpha(view);
if (alpha >= 0) {
Drawable replaced = checkAndReplaceDrawable(drawable, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, drawable);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
view.setBackground(replaced);
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
} else {
view.setBackground(drawable);
}
} else {
view.setBackground(drawable);
}
}
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "setBackground")
@ReplaceInvoke
public static void setBackground(View view, Drawable drawable) {
if (view == null) {
return;
}
if (!view.isLongClickable() && !view.isClickable()) {
view.setBackground(drawable);
return;
}
float alpha = getAlpha(view);
if (alpha >= 0) {
Drawable replaced = checkAndReplaceDrawable(drawable, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, drawable);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
view.setBackground(replaced);
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
} else {
view.setBackground(drawable);
}
} else {
view.setBackground(drawable);
}
}
@TargetClass(value = "android.widget.ImageView", scope = Scope.ALL)
@TargetMethod(methodName = "setImageDrawable")
@ReplaceInvoke
public static void setImageViewDrawable(ImageView view, Drawable drawable) {
if (view == null) {
return;
}
if (!view.isLongClickable() && !view.isClickable()) {
view.setImageDrawable(drawable);
return;
}
float alpha = getAlpha(view);
if (alpha >= 0.0) {
Drawable replaced = checkAndReplaceDrawable(drawable, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, drawable);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
view.setImageDrawable(replaced);
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
} else {
view.setImageDrawable(drawable);
}
} else {
view.setImageDrawable(drawable);
}
}
@TargetClass(value = "android.widget.ImageView", scope = Scope.ALL)
@TargetMethod(methodName = "setImageResource")
@ReplaceInvoke
public static void setImageViewResource(ImageView view, int resId) {
if (view == null) {
return;
}
if (!view.isLongClickable() && !view.isClickable()) {
view.setImageResource(resId);
return;
}
float alpha = getAlpha(view);
if (alpha >= 0.0) {
Drawable drawable = ContextCompat.getDrawable(view.getContext(), resId);
Drawable replaced = checkAndReplaceDrawable(drawable, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, drawable);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
view.setImageDrawable(replaced);
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
} else {
view.setImageDrawable(drawable);
}
} else {
view.setImageResource(resId);
}
}
public static float getAlpha(View view) {
Object tag = view.getTag(R.id.click_pressed_attr_enabled);
if (tag != null && !((Boolean) tag)) {
return -1.0f;
}
tag = view.getTag(R.id.click_pressed_attr_id);
if (tag instanceof AttributeSet) {
AttributeSet attr = (AttributeSet) tag;
TypedArray array = null;
try {
array = view.getContext().obtainStyledAttributes(attr, R.styleable.ClickPressedStyle);
return array.getFloat(R.styleable.ClickPressedStyle_pressed_alpha, 0.6f);
} finally {
if (array != null) {
array.recycle();
}
}
}
return -1.0f;
}
@ImplementedInterface(value = "android.view.LayoutInflater$Factory", scope = Scope.LEAF)
@Insert(mayCreateSuper = true)
@TargetMethod(methodName = "onCreateView")
public View onCreateView(String name, Context context, AttributeSet attrs) {
View view = (View) Origin.call();
if (view == null && attrs != null) {
view = tryCreateView(name, context, attrs);
}
checkSetBgIfNeed(null, view, attrs, false);
return view;
}
@ImplementedInterface(value = "android.view.LayoutInflater$Factory2", scope = Scope.LEAF)
@Insert(mayCreateSuper = true)
@TargetMethod(methodName = "onCreateView")
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
View view = (View) Origin.call();
if (view == null && attrs != null) {
view = tryCreateView(name, context, attrs);
}
checkSetBgIfNeed(parent, view, attrs, false);
return view;
}
@Nullable
private static View tryCreateView(String name, Context context, AttributeSet attrs) {
View ret = null;
if (name != null && name.length() > 0) {
if (context != null) {
try {
ret = LayoutInflater.from(context).createView(name, null, attrs);
} catch (ClassNotFoundException ignore) {}
if (ret == null) {
String[] prefixList = {
"android.widget.",
"android.webkit.",
"android.app."
};
for (String prefix : prefixList) {
try {
ret = LayoutInflater.from(context).createView(name, prefix, attrs);
} catch (ClassNotFoundException ignore) { }
}
}
}
}
return ret;
}
private static void checkSetBgIfNeed(View parent, View view, AttributeSet attr, boolean check) {
try {
TypedArray t = null;
float alpha = 0.6f;
boolean enabled;
try {
if (parent == null && view == null) {
return;
}
Context context = parent == null ? view.getContext() : parent.getContext();
if (context == null) {
return;
}
if (parent != null) {
Object tag = parent.getTag(R.id.click_pressed_attr_enabled);
if (tag != null && !((Boolean) tag)) {
view.setTag(R.id.click_pressed_attr_enabled, false);
return;
}
}
if (view != null) {
Object tag = view.getTag(R.id.click_pressed_attr_enabled);
if (tag != null && !((Boolean) tag)) {
view.setTag(R.id.click_pressed_attr_enabled, false);
return;
}
if (attr != null) {
t = context.obtainStyledAttributes(attr, R.styleable.ClickPressedStyle);
enabled = t.getBoolean(R.styleable.ClickPressedStyle_pressed_enabled, true);
if (!enabled) {
view.setTag(R.id.click_pressed_attr_enabled, false);
return;
}
alpha = t.getFloat(R.styleable.ClickPressedStyle_pressed_alpha, 0.6f);
if (alpha < 0.0f || alpha > 1.0f) {
throw new AssertionError("view custom attr \\'alpha\\' must be in [0.0, 1.0]");
}
}
if (!check) {
view.setTag(R.id.click_pressed_attr_id, attr);
return;
}
}
} finally {
if (t != null) {
t.recycle();
}
}
boolean rst = check(view, alpha);
if (!rst && view != null) {
view.setTag(R.id.click_pressed_attr_enabled, false);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
private static boolean check(View view, float alpha) {
if (view instanceof ImageView) {
ImageView image = (ImageView) view;
Drawable old = image.getBackground();
Drawable replaced = checkAndReplaceDrawable(old, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, old);
image.setBackground(replaced);
return true;
}
old = image.getDrawable();
replaced = checkAndReplaceDrawable(old, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, old);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
image.setImageDrawable(replaced);
image.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
return true;
}
return false;
}
if (view instanceof TextView) {
TextView text = (TextView) view;
Drawable background = text.getBackground();
Drawable replaced = checkAndReplaceDrawable(background, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, background);
int paddingLeft = text.getPaddingLeft();
int paddingRight = text.getPaddingRight();
int paddingTop = text.getPaddingTop();
int paddingBottom = text.getPaddingBottom();
text.setBackground(replaced);
text.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
return true;
}
ColorStateList textColor = text.getTextColors();
if (textColor != null) {
int current = text.getCurrentTextColor();
int pressed = textColor.getColorForState(new int[]{ android.R.attr.state_pressed }, Integer.MIN_VALUE);
if (pressed != Integer.MIN_VALUE && pressed != current) {
return false;
}
int enableColor = textColor.getColorForState(new int[] { android.R.attr.state_enabled }, Integer.MIN_VALUE);
int defaultColor = current;
if (enableColor == Integer.MIN_VALUE && enableColor != current) {
defaultColor = textColor.getDefaultColor();
}
int pressedColor = Color.argb((int)(Color.alpha(defaultColor) * alpha), Color.red(defaultColor), Color.green(defaultColor), Color.blue(defaultColor));
int disableColor = textColor.getColorForState(new int[] { -android.R.attr.state_enabled }, Integer.MIN_VALUE);
int size = 2;
if (disableColor != Integer.MIN_VALUE && disableColor != current) {
size += 1;
}
boolean hasChecked = false;
int checkedColor = textColor.getColorForState(new int[] { android.R.attr.state_checked }, Integer.MIN_VALUE);
if (checkedColor != Integer.MIN_VALUE && checkedColor != current) {
hasChecked = true;
size += 1;
}
boolean hasUnChecked = false;
int unCheckedColor = textColor.getColorForState(new int[]{ -android.R.attr.state_checked }, Integer.MIN_VALUE);
if (unCheckedColor != Integer.MIN_VALUE && unCheckedColor != current) {
hasUnChecked = true;
size += 1;
}
int[][] states = new int[size][1];
int[] colors = new int[size];
states[0] = new int[] { android.R.attr.state_pressed };
colors[0] = pressedColor;
if (size > 2) {
states[1] = new int[] { -android.R.attr.state_enabled };
colors[1] = disableColor;
states[2] = new int[] { android.R.attr.state_enabled };
colors[2] = defaultColor;
if (hasChecked) {
states[3] = new int[] { android.R.attr.state_checked };
colors[3] = checkedColor;
}
if (hasUnChecked) {
if (size > 4) {
states[4] = new int[] { -android.R.attr.state_checked };
colors[4] = unCheckedColor;
} else {
states[3] = new int[] { -android.R.attr.state_checked };
colors[3] = unCheckedColor;
}
}
} else {
states[1] = new int[] { -android.R.attr.state_pressed };
colors[1] = defaultColor;
}
ColorStateList newColor = new ColorStateList(states, colors);
text.setTag(R.id.click_pressed_attr_replaced_color, textColor);
text.setTextColor(newColor);
return true;
}
return false;
}
if (view != null) {
Drawable old = view.getBackground();
Drawable replaced = checkAndReplaceDrawable(old, alpha);
if (replaced != null) {
view.setTag(R.id.click_pressed_attr_replaced, old);
int paddingLeft = view.getPaddingLeft();
int paddingRight = view.getPaddingRight();
int paddingTop = view.getPaddingTop();
int paddingBottom = view.getPaddingBottom();
view.setBackground(replaced);
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
return true;
}
}
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
View child = group.getChildAt(i);
if (check(child, alpha)) {
return true;
}
}
}
return false;
}
private static Drawable checkAndReplaceDrawable(Drawable old, float alpha) {
if (old == null) {
return null;
}
if (old instanceof StateListDrawable) {
StateListDrawable drawable = (StateListDrawable) old;
int[] states = drawable.getState();
boolean hasPressed = false;
for (int state : states) {
if (state == android.R.attr.state_pressed) {
hasPressed = true;
break;
}
}
if (hasPressed) {
return null;
}
Drawable origin = drawable.getCurrent();
Drawable.ConstantState constantState = origin.getConstantState();
if (constantState != null) {
Drawable pressed = DrawableCompat.wrap(constantState.newDrawable().mutate());
pressed.setAlpha((int)(255 * alpha));
drawable.addState(new int[] { android.R.attr.state_pressed }, pressed);
return drawable;
}
return null;
}
Drawable.ConstantState constantState = old.getConstantState();
if (constantState != null) {
StateListDrawable result = new StateListDrawable();
int[] state = { -android.R.attr.state_pressed };
result.addState(state, old);
Drawable pressed = DrawableCompat.wrap(constantState.newDrawable().mutate());
pressed.setAlpha((int)(255 * alpha));
result.addState(new int[] { android.R.attr.state_pressed }, pressed);
return result;
}
return null;
}
}