• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static org.robolectric.res.android.AttributeResolution.STYLE_ASSET_COOKIE;
4 import static org.robolectric.res.android.AttributeResolution.STYLE_CHANGING_CONFIGURATIONS;
5 import static org.robolectric.res.android.AttributeResolution.STYLE_DATA;
6 import static org.robolectric.res.android.AttributeResolution.STYLE_DENSITY;
7 import static org.robolectric.res.android.AttributeResolution.STYLE_NUM_ENTRIES;
8 import static org.robolectric.res.android.AttributeResolution.STYLE_RESOURCE_ID;
9 import static org.robolectric.res.android.AttributeResolution.STYLE_TYPE;
10 import static org.robolectric.shadow.api.Shadow.directlyOn;
11 
12 import android.annotation.StyleableRes;
13 import android.content.res.Resources;
14 import android.content.res.TypedArray;
15 import android.os.Build;
16 import android.util.TypedValue;
17 import com.google.common.base.Strings;
18 import com.google.common.collect.ImmutableMap;
19 import org.robolectric.RuntimeEnvironment;
20 import org.robolectric.annotation.HiddenApi;
21 import org.robolectric.annotation.Implementation;
22 import org.robolectric.annotation.Implements;
23 import org.robolectric.annotation.RealObject;
24 import org.robolectric.shadow.api.Shadow;
25 import org.robolectric.util.ReflectionHelpers;
26 import org.robolectric.util.ReflectionHelpers.ClassParameter;
27 
28 @SuppressWarnings({"UnusedDeclaration"})
29 @Implements(TypedArray.class)
30 public class ShadowTypedArray {
31   @RealObject private TypedArray realTypedArray;
32   private CharSequence[] stringData;
33   public String positionDescription;
34 
create(Resources realResources, int[] attrs, int[] data, int[] indices, int len, CharSequence[] stringData)35   public static TypedArray create(Resources realResources, int[] attrs, int[] data, int[] indices, int len, CharSequence[] stringData) {
36     TypedArray typedArray;
37     if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) {
38       typedArray = ReflectionHelpers.callConstructor(TypedArray.class,
39           ClassParameter.from(Resources.class, realResources));
40       ReflectionHelpers.setField(typedArray, "mData", data);
41       ReflectionHelpers.setField(typedArray, "mLength", len);
42       ReflectionHelpers.setField(typedArray, "mIndices", indices);
43     } else {
44       typedArray = ReflectionHelpers.callConstructor(TypedArray.class,
45           ClassParameter.from(Resources.class, realResources),
46           ClassParameter.from(int[].class, data),
47           ClassParameter.from(int[].class, indices),
48           ClassParameter.from(int.class, len));
49     }
50 
51     ShadowTypedArray shadowTypedArray = Shadow.extract(typedArray);
52     shadowTypedArray.stringData = stringData;
53     return typedArray;
54   }
55 
56   @HiddenApi @Implementation
loadStringValueAt(int index)57   protected CharSequence loadStringValueAt(int index) {
58     if (ShadowAssetManager.useLegacy()) {
59       return stringData[index / STYLE_NUM_ENTRIES];
60     } else {
61       return directlyOn(realTypedArray, TypedArray.class, "loadStringValueAt",
62           new ClassParameter(int.class, index));
63     }
64   }
65 
66   @Implementation
getNonResourceString(@tyleableRes int index)67   protected String getNonResourceString(@StyleableRes int index) {
68     return directlyOn(realTypedArray, TypedArray.class).getString(index);
69   }
70 
71   @Implementation
getNonConfigurationString(@tyleableRes int index, int allowedChangingConfigs)72   protected String getNonConfigurationString(@StyleableRes int index, int allowedChangingConfigs) {
73     return directlyOn(realTypedArray, TypedArray.class).getString(index);
74   }
75 
76   @Implementation
getPositionDescription()77   protected String getPositionDescription() {
78     if (ShadowAssetManager.useLegacy()) {
79       return positionDescription;
80     } else {
81       return directlyOn(realTypedArray, TypedArray.class, "getPositionDescription");
82     }
83   }
84 
dump(TypedArray typedArray)85   public static void dump(TypedArray typedArray) {
86     int[] data = ReflectionHelpers.getField(typedArray, "mData");
87 
88     StringBuilder result = new StringBuilder();
89     for (int index = 0; index < data.length; index+= STYLE_NUM_ENTRIES) {
90       final int type = data[index+STYLE_TYPE];
91       result.append("Index: ").append(index / STYLE_NUM_ENTRIES).append(System.lineSeparator());
92       result.append(Strings.padEnd("Type: ", 25, ' ')).append(TYPE_MAP.get(type)).append(System.lineSeparator());
93       if (type != TypedValue.TYPE_NULL) {
94         result.append(Strings.padEnd("Style data: ", 25, ' ')).append(data[index+ STYLE_DATA]).append(System.lineSeparator());
95         result.append(Strings.padEnd("Asset cookie ", 25, ' ')).append(data[index+STYLE_ASSET_COOKIE]).append(System.lineSeparator());
96         result.append(Strings.padEnd("Style resourceId: ", 25, ' ')).append(data[index+ STYLE_RESOURCE_ID]).append(System.lineSeparator());
97         result.append(Strings.padEnd("Changing configurations ", 25, ' ')).append(data[index+STYLE_CHANGING_CONFIGURATIONS]).append(System.lineSeparator());
98         result.append(Strings.padEnd("Style density: ", 25, ' ')).append(data[index+STYLE_DENSITY]).append(System.lineSeparator());
99         if (type == TypedValue.TYPE_STRING) {
100           ShadowTypedArray shadowTypedArray = Shadow.extract(typedArray);
101           result.append(Strings.padEnd("Style value: ", 25, ' ')).append(shadowTypedArray.loadStringValueAt(index)).append(System.lineSeparator());
102         }
103       }
104       result.append(System.lineSeparator());
105     }
106     System.out.println(result.toString());
107   }
108 
109   private static final ImmutableMap<Integer, String> TYPE_MAP = ImmutableMap.<Integer, String>builder()
110           .put(TypedValue.TYPE_NULL, "TYPE_NULL")
111           .put(TypedValue.TYPE_REFERENCE, "TYPE_REFERENCE")
112           .put(TypedValue.TYPE_ATTRIBUTE, "TYPE_ATTRIBUTE")
113           .put(TypedValue.TYPE_STRING, "TYPE_STRING")
114           .put(TypedValue.TYPE_FLOAT, "TYPE_FLOAT")
115           .put(TypedValue.TYPE_DIMENSION, "TYPE_DIMENSION")
116           .put(TypedValue.TYPE_FRACTION, "TYPE_FRACTION")
117           .put(TypedValue.TYPE_INT_DEC, "TYPE_INT_DEC")
118           .put(TypedValue.TYPE_INT_HEX, "TYPE_INT_HEX")
119           .put(TypedValue.TYPE_INT_BOOLEAN, "TYPE_INT_BOOLEAN")
120           .put(TypedValue.TYPE_INT_COLOR_ARGB8, "TYPE_INT_COLOR_ARGB8")
121           .put(TypedValue.TYPE_INT_COLOR_RGB8, "TYPE_INT_COLOR_RGB8")
122           .put(TypedValue.TYPE_INT_COLOR_ARGB4, "TYPE_INT_COLOR_ARGB4")
123           .put(TypedValue.TYPE_INT_COLOR_RGB4, "TYPE_INT_COLOR_RGB4")
124           .build();
125 
126 }
127