From a6f354b78ecba3add458df2857d4fbd7b3f0dcbc Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Mon, 18 May 2015 15:26:57 -0700 Subject: [PATCH] Avoid strict mode violation during saveAttributeData Adds a new framework-private method for obtaining a string without throwing a strict mode violation on coercion. Bug: 21109507 Change-Id: I5a7f091fc92d5abfde9e1c31f30d59ed02c7569b --- core/java/android/content/res/TypedArray.java | 23 +++++++++- core/java/android/view/View.java | 65 ++++++++++++++++----------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 1fca9204fe42..f0c3f2d2884b 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -181,7 +181,26 @@ public class TypedArray { * not be coerced to a string. * @throws RuntimeException if the TypedArray has already been recycled. */ + @Nullable public String getString(int index) { + return getString(index, true); + } + + /** + * Returns a string representation of the value at the given index, + * optionally throwing a resource mismatch strict mode violation if the + * value must be coerced to a string. + * + * @param index the index of the attribute to retrieve + * @param strict {@code true} to throw a strict mode violation for string + * coercion, {@code false} otherwise + * @return a string representation of the value at the given index, or + * {@code null} if the resource could not be coerced to a string + * @see StrictMode#noteResourceMismatch(Object) + * @hide Used internally for view attribute inspection. + */ + @Nullable + public String getString(int index, boolean strict) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } @@ -197,7 +216,9 @@ public class TypedArray { final TypedValue v = mValue; if (getValueAt(index, v)) { - StrictMode.noteResourceMismatch(v); + if (strict) { + StrictMode.noteResourceMismatch(v); + } final CharSequence cs = v.coerceToString(); return cs != null ? cs.toString() : null; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6ca320ab4c1f..c40a340ea3f6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4454,47 +4454,60 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static SparseArray getAttributeMap() { if (mAttributeMap == null) { - mAttributeMap = new SparseArray(); + mAttributeMap = new SparseArray<>(); } return mAttributeMap; } - private void saveAttributeData(AttributeSet attrs, TypedArray a) { - int length = ((attrs == null ? 0 : attrs.getAttributeCount()) + a.getIndexCount()) * 2; - mAttributes = new String[length]; + private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { + final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); + final int indexCount = t.getIndexCount(); + final String[] attributes = new String[(attrsCount + indexCount) * 2]; int i = 0; - if (attrs != null) { - for (i = 0; i < attrs.getAttributeCount(); i += 2) { - mAttributes[i] = attrs.getAttributeName(i); - mAttributes[i + 1] = attrs.getAttributeValue(i); - } + // Store raw XML attributes. + for (int j = 0; j < attrsCount; ++j) { + attributes[i] = attrs.getAttributeName(j); + attributes[i + 1] = attrs.getAttributeValue(j); + i += 2; } - SparseArray attributeMap = getAttributeMap(); - for (int j = 0; j < a.length(); ++j) { - if (a.hasValue(j)) { - try { - int resourceId = a.getResourceId(j, 0); - if (resourceId == 0) { - continue; - } + // Store resolved styleable attributes. + final Resources res = t.getResources(); + final SparseArray attributeMap = getAttributeMap(); + for (int j = 0; j < indexCount; ++j) { + final int index = t.getIndex(j); + if (!t.hasValueOrEmpty(index)) { + // Value is undefined. Skip it. + continue; + } - String resourceName = attributeMap.get(resourceId); - if (resourceName == null) { - resourceName = a.getResources().getResourceName(resourceId); - attributeMap.put(resourceId, resourceName); - } + final int resourceId = t.getResourceId(index, 0); + if (resourceId == 0) { + // Value is not a reference. Skip it. + continue; + } - mAttributes[i] = resourceName; - mAttributes[i + 1] = a.getText(j).toString(); - i += 2; + String resourceName = attributeMap.get(resourceId); + if (resourceName == null) { + try { + resourceName = res.getResourceName(resourceId); } catch (Resources.NotFoundException e) { - // if we can't get the resource name, we just ignore it + resourceName = "0x" + Integer.toHexString(resourceId); } + attributeMap.put(resourceId, resourceName); } + + attributes[i] = resourceName; + attributes[i + 1] = t.getString(index, false); + i += 2; } + + // Trim to fit contents. + final String[] trimmed = new String[i]; + System.arraycopy(attributes, 0, trimmed, 0, i); + mAttributes = trimmed; } public String toString() { -- 2.11.0