From d59cc6b784792d4ade83c3c010203f5c83181dfb Mon Sep 17 00:00:00 2001 From: LoveSy Date: Mon, 10 Jan 2022 20:51:56 +0800 Subject: [PATCH] Enhance resources hook (#1524) 1. Fix missing `getFloat` overload for XResources 2. Fix missing `getFont` overload 3. Add `getValue` and `getValueForDensity` replacement for apps that obtain raw values --- .../java/android/content/res/XResources.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/core/src/main/java/android/content/res/XResources.java b/core/src/main/java/android/content/res/XResources.java index 483e1133..da9be30d 100644 --- a/core/src/main/java/android/content/res/XResources.java +++ b/core/src/main/java/android/content/res/XResources.java @@ -23,6 +23,7 @@ package android.content.res; import static org.lsposed.lspd.nativebridge.ResourcesHook.rewriteXmlReferencesNative; import static de.robv.android.xposed.XposedHelpers.decrementMethodDepth; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; +import static de.robv.android.xposed.XposedHelpers.getBooleanField; import static de.robv.android.xposed.XposedHelpers.getLongField; import static de.robv.android.xposed.XposedHelpers.getObjectField; import static de.robv.android.xposed.XposedHelpers.incrementMethodDepth; @@ -32,8 +33,10 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.graphics.Color; import android.graphics.Movie; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.StrictMode; import android.text.Html; import android.util.AttributeSet; @@ -44,6 +47,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.RequiresApi; + import org.xmlpull.v1.XmlPullParser; import java.io.File; @@ -860,6 +865,35 @@ public class XResources extends XResourcesSuperClass { } } + /** @hide */ + @RequiresApi(Build.VERSION_CODES.Q) + @Override + public float getFloat(int id) { + Object replacement = getReplacement(id); + if (replacement instanceof Float) { + return (Float) replacement; + } else if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + return repRes.getFloat(repId); + } + return super.getFloat(id); + } + + /** @hide */ + @Override + public Typeface getFont(int id) { + Object replacement = getReplacement(id); + if (replacement instanceof Typeface) { + return (Typeface) replacement; + } else if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + return repRes.getFont(repId); + } + return super.getFont(id); + } + /** @hide */ @Override public float getFraction(int id, int base, int pbase) { @@ -1055,6 +1089,38 @@ public class XResources extends XResourcesSuperClass { return super.getTextArray(id); } + /** @hide */ + @Override + public void getValue(int id, TypedValue outValue, boolean resolveRefs) throws NotFoundException { + Object replacement = getReplacement(id); + if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + repRes.getValue(repId, outValue, resolveRefs); + } else { + if (replacement != null) { + XposedBridge.log("Replacement of resource ID #0x" + Integer.toHexString(id) + " escaped because of deprecated replacement. Please use XResForwarder instead."); + } + super.getValue(id, outValue, resolveRefs); + } + } + + /** @hide */ + @Override + public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs) throws NotFoundException { + Object replacement = getReplacement(id); + if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + repRes.getValueForDensity(repId, density, outValue, resolveRefs); + } else { + if (replacement != null) { + XposedBridge.log("Replacement of resource ID #0x" + Integer.toHexString(id) + " escaped because of deprecated replacement. Please use XResForwarder instead."); + } + super.getValueForDensity(id, density, outValue, resolveRefs); + } + } + /** @hide */ @Override public XmlResourceParser getXml(int id) throws NotFoundException { @@ -1337,6 +1403,19 @@ public class XResources extends XResourcesSuperClass { return super.getFloat(index, defValue); } + @Override + public Typeface getFont(int index) { + Object replacement = ((XResources) getResources()).getReplacement(getResourceId(index, 0)); + if (replacement instanceof Typeface) { + return (Typeface) replacement; + } else if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + return repRes.getFont(repId); + } + return super.getFont(index); + } + @Override public float getFraction(int index, int base, int pbase, float defValue) { Object replacement = ((XResources) getResources()).getReplacement(getResourceId(index, 0)); @@ -1435,6 +1514,44 @@ public class XResources extends XResourcesSuperClass { } return super.getTextArray(index); } + + @Override + public boolean getValue(int index, TypedValue outValue) { + var id = getResourceId(index, 0); + Object replacement = ((XResources) getResources()).getReplacement(id); + if (replacement instanceof XResForwarder) { + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + repRes.getValue(repId, outValue, true); + return outValue.type != TypedValue.TYPE_NULL; + } else { + if (replacement != null) { + XposedBridge.log("Replacement of resource ID #0x" + Integer.toHexString(id) + " escaped because of deprecated replacement. Please use XResForwarder instead."); + } + return super.getValue(index, outValue); + } + } + + @Override + public TypedValue peekValue(int index) { + var id = getResourceId(index, 0); + Object replacement = ((XResources) getResources()).getReplacement(id); + if (replacement instanceof XResForwarder) { + if (getBooleanField(this, "mRecycled")) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + final TypedValue value = (TypedValue) getObjectField(this, "mValue"); + Resources repRes = ((XResForwarder) replacement).getResources(); + int repId = ((XResForwarder) replacement).getId(); + repRes.getValue(repId, value, true); + return value; + } else { + if (replacement != null) { + XposedBridge.log("Replacement of resource ID #0x" + Integer.toHexString(id) + " escaped because of deprecated replacement. Please use XResForwarder instead."); + } + return super.peekValue(index); + } + } }