diff --git a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java index 53d49dfca..3faf6eaf1 100644 --- a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java @@ -1,18 +1,23 @@ package jadx.core.utils.android; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.android.dx.rop.code.AccessFlags; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.core.codegen.ClassGen; import jadx.core.codegen.CodeWriter; +import jadx.core.deobf.NameMapper; import jadx.core.dex.attributes.AType; +import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.ClassInfo; +import jadx.core.dex.info.ConstStorage; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.ClassNode; @@ -86,6 +91,7 @@ public class AndroidResourcesUtils { } private static void addResourceFields(ClassNode resCls, ResourceStorage resStorage, boolean rClsExists) { + Map resFieldsMap = fillResFieldsMap(resCls); Map innerClsMap = new TreeMap<>(); if (rClsExists) { for (ClassNode innerClass : resCls.getInnerClasses()) { @@ -93,18 +99,14 @@ public class AndroidResourcesUtils { } } for (ResourceEntry resource : resStorage.getResources()) { - ClassNode typeCls = innerClsMap.computeIfAbsent(resource.getTypeName(), name -> { - ClassNode newTypeCls = new ClassNode(resCls.dex(), resCls.getFullName() + "$" + name, - AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL); - resCls.addInnerClass(newTypeCls); - if (rClsExists) { - newTypeCls.addAttr(AType.COMMENTS, "added by JADX"); - } - return newTypeCls; - }); - FieldNode rField = typeCls.searchFieldByName(resource.getKeyName()); + ClassNode typeCls = innerClsMap.computeIfAbsent( + resource.getTypeName(), + name -> addClassForResType(resCls, rClsExists, name) + ); + String resName = resource.getKeyName(); + FieldNode rField = typeCls.searchFieldByName(resName); if (rField == null) { - FieldInfo rFieldInfo = FieldInfo.from(typeCls.dex(), typeCls.getClassInfo(), resource.getKeyName(), ArgType.INT); + FieldInfo rFieldInfo = FieldInfo.from(typeCls.dex(), typeCls.getClassInfo(), resName, ArgType.INT); rField = new FieldNode(typeCls, rFieldInfo, AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL); rField.addAttr(FieldInitAttr.constValue(resource.getId())); typeCls.getFields().add(rField); @@ -112,6 +114,42 @@ public class AndroidResourcesUtils { rField.addAttr(AType.COMMENTS, "added by JADX"); } } + FieldNode fieldNode = resFieldsMap.get(resource.getId()); + if (fieldNode != null + && !fieldNode.getName().equals(resName) + && NameMapper.isValidIdentifier(resName)) { + fieldNode.getFieldInfo().setAlias(resName); + } } } + + @NotNull + private static ClassNode addClassForResType(ClassNode resCls, boolean rClsExists, String typeName) { + ClassNode newTypeCls = new ClassNode(resCls.dex(), resCls.getFullName() + "$" + typeName, + AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL); + resCls.addInnerClass(newTypeCls); + if (rClsExists) { + newTypeCls.addAttr(AType.COMMENTS, "added by JADX"); + } + return newTypeCls; + } + + @NotNull + private static Map fillResFieldsMap(ClassNode resCls) { + Map resFieldsMap = new HashMap<>(); + ConstStorage constStorage = resCls.root().getConstValues(); + Map constFields = constStorage.getGlobalConstFields(); + for (Map.Entry entry : constFields.entrySet()) { + Object key = entry.getKey(); + FieldNode field = entry.getValue(); + AccessInfo accessFlags = field.getAccessFlags(); + if (field.getType().equals(ArgType.INT) + && accessFlags.isStatic() + && accessFlags.isFinal() + && key instanceof Integer) { + resFieldsMap.put((Integer) key, field); + } + } + return resFieldsMap; + } }