am ba5a02c5: LayoutLib: Support getting resource arrays. [DO NOT MERGE]
* commit 'ba5a02c5aa3c9850cdd72e592e9fa8a8d92db7ef': LayoutLib: Support getting resource arrays. [DO NOT MERGE]
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import com.android.SdkConstants;
|
||||
import com.android.ide.common.rendering.api.ArrayResourceValue;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.ide.common.rendering.api.LayoutlibCallback;
|
||||
import com.android.ide.common.rendering.api.ResourceValue;
|
||||
@@ -32,6 +34,8 @@ import com.android.util.Pair;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -42,6 +46,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -241,6 +246,145 @@ public final class BridgeResources extends Resources {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence[] getTextArray(int id) throws NotFoundException {
|
||||
ResourceValue resValue = getArrayResourceValue(id);
|
||||
if (resValue == null) {
|
||||
// Error already logged by getArrayResourceValue.
|
||||
return new CharSequence[0];
|
||||
} else if (!(resValue instanceof ArrayResourceValue)) {
|
||||
return new CharSequence[]{
|
||||
resolveReference(resValue.getValue(), resValue.isFramework())};
|
||||
}
|
||||
ArrayResourceValue arv = ((ArrayResourceValue) resValue);
|
||||
return fillValues(arv, new CharSequence[arv.getElementCount()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getStringArray(int id) throws NotFoundException {
|
||||
ResourceValue resValue = getArrayResourceValue(id);
|
||||
if (resValue == null) {
|
||||
// Error already logged by getArrayResourceValue.
|
||||
return new String[0];
|
||||
} else if (!(resValue instanceof ArrayResourceValue)) {
|
||||
return new String[]{
|
||||
resolveReference(resValue.getValue(), resValue.isFramework())};
|
||||
}
|
||||
ArrayResourceValue arv = ((ArrayResourceValue) resValue);
|
||||
return fillValues(arv, new String[arv.getElementCount()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve each element in resValue and copy them to {@code values}. The values copied are
|
||||
* always Strings. The ideal signature for the method should be <T super String>, but java
|
||||
* generics don't support it.
|
||||
*/
|
||||
private <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
|
||||
int i = 0;
|
||||
for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T s = (T) resolveReference(iterator.next(), resValue.isFramework());
|
||||
values[i] = s;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIntArray(int id) throws NotFoundException {
|
||||
ResourceValue rv = getArrayResourceValue(id);
|
||||
if (rv == null) {
|
||||
// Error already logged by getArrayResourceValue.
|
||||
return new int[0];
|
||||
} else if (!(rv instanceof ArrayResourceValue)) {
|
||||
// This is an older IDE that can only give us the first element of the array.
|
||||
String firstValue = resolveReference(rv.getValue(), rv.isFramework());
|
||||
try {
|
||||
return new int[]{getInt(firstValue)};
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
"Integer resource array contains non-integer value: " +
|
||||
firstValue, null);
|
||||
return new int[1];
|
||||
}
|
||||
}
|
||||
ArrayResourceValue resValue = ((ArrayResourceValue) rv);
|
||||
int[] values = new int[resValue.getElementCount()];
|
||||
int i = 0;
|
||||
for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
|
||||
String element = resolveReference(iterator.next(), resValue.isFramework());
|
||||
try {
|
||||
values[i] = getInt(element);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
"Integer resource array contains non-integer value: " + element, null);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the ArrayResourceValue for the given id.
|
||||
* <p/>
|
||||
* If the ResourceValue found is not of type {@link ResourceType#ARRAY}, the method logs an
|
||||
* error and return null. However, if the ResourceValue found has type {@code
|
||||
* ResourceType.ARRAY}, but the value is not an instance of {@link ArrayResourceValue}, the
|
||||
* method returns the ResourceValue. This happens on older versions of the IDE, which did not
|
||||
* parse the array resources properly.
|
||||
* <p/>
|
||||
* @throws NotFoundException if no resource if found
|
||||
*/
|
||||
@Nullable
|
||||
private ResourceValue getArrayResourceValue(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (v != null) {
|
||||
ResourceValue resValue = v.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
final ResourceType type = resValue.getResourceType();
|
||||
if (type != ResourceType.ARRAY) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
|
||||
String.format(
|
||||
"Resource with id 0x%1$X is not an array resource, but %2$s",
|
||||
id, type == null ? "null" : type.getDisplayName()),
|
||||
null);
|
||||
return null;
|
||||
}
|
||||
if (!(resValue instanceof ArrayResourceValue)) {
|
||||
Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
|
||||
"Obtaining resource arrays via getTextArray, getStringArray or getIntArray is not fully supported in this version of the IDE.",
|
||||
null);
|
||||
}
|
||||
return resValue;
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String resolveReference(@NonNull String ref, boolean forceFrameworkOnly) {
|
||||
if (ref.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || ref.startsWith
|
||||
(SdkConstants.PREFIX_THEME_REF)) {
|
||||
ResourceValue rv =
|
||||
mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
|
||||
rv = mContext.getRenderResources().resolveResValue(rv);
|
||||
if (rv != null) {
|
||||
return rv.getValue();
|
||||
} else {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
|
||||
"Unable to resolve resource " + ref, null);
|
||||
}
|
||||
}
|
||||
// Not a reference.
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlResourceParser getLayout(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
|
||||
@@ -431,13 +575,8 @@ public final class BridgeResources extends Resources {
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
int radix = 10;
|
||||
if (v.startsWith("0x")) {
|
||||
v = v.substring(2);
|
||||
radix = 16;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(v, radix);
|
||||
return getInt(v);
|
||||
} catch (NumberFormatException e) {
|
||||
// return exception below
|
||||
}
|
||||
@@ -610,7 +749,6 @@ public final class BridgeResources extends Resources {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InputStream openRawResource(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
@@ -691,7 +829,7 @@ public final class BridgeResources extends Resources {
|
||||
resourceInfo = mLayoutlibCallback.resolveResourceId(id);
|
||||
}
|
||||
|
||||
String message = null;
|
||||
String message;
|
||||
if (resourceInfo != null) {
|
||||
message = String.format(
|
||||
"Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
|
||||
@@ -703,4 +841,15 @@ public final class BridgeResources extends Resources {
|
||||
|
||||
throw new NotFoundException(message);
|
||||
}
|
||||
|
||||
private int getInt(String v) throws NumberFormatException {
|
||||
int radix = 10;
|
||||
if (v.startsWith("0x")) {
|
||||
v = v.substring(2);
|
||||
radix = 16;
|
||||
} else if (v.startsWith("0")) {
|
||||
radix = 8;
|
||||
}
|
||||
return Integer.parseInt(v, radix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.1.3'
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
@@ -19,12 +19,12 @@ allprojects {
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
compileSdkVersion 22
|
||||
buildToolsVersion '21.1.2'
|
||||
defaultConfig {
|
||||
applicationId 'com.android.layoutlib.test.myapplication'
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 21
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 22
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
@@ -0,0 +1,41 @@
|
||||
package com.android.layoutlib.test.myapplication;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A widget to test obtaining arrays from resources.
|
||||
*/
|
||||
public class ArraysCheckWidget extends LinearLayout {
|
||||
public ArraysCheckWidget(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ArraysCheckWidget(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public ArraysCheckWidget(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
Resources resources = context.getResources();
|
||||
for (CharSequence chars : resources.getTextArray(R.array.array)) {
|
||||
addTextView(context, chars);
|
||||
}
|
||||
for (int i : resources.getIntArray(R.array.int_array)) {
|
||||
addTextView(context, String.valueOf(i));
|
||||
}
|
||||
for (String string : resources.getStringArray(R.array.string_array)) {
|
||||
addTextView(context, string);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTextView(Context context, CharSequence string) {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setText(string);
|
||||
textView.setTextSize(30);
|
||||
addView(textView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.android.layoutlib.test.myapplication.ArraysCheckWidget xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</com.android.layoutlib.test.myapplication.ArraysCheckWidget>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="array">
|
||||
<item>first</item>
|
||||
<item>second</item>
|
||||
</array>
|
||||
<integer-array name="int_array">
|
||||
<item>1</item>
|
||||
<item>0xaB</item> <!-- hex entry (decimal 171) -->
|
||||
<item>010</item> <!-- octal entry -->
|
||||
<item>@integer/ten</item> <!-- value reference -->
|
||||
<item>?attr/myattr</item> <!-- theme attr reference -->
|
||||
</integer-array>
|
||||
<string-array name="string_array">
|
||||
<item>mystring</item>
|
||||
<item>@string/hello_world</item> <!-- string ref in appNs -->
|
||||
<!-- theme ref in android NS. value = @string/candidates_style = <u>candidates</u> -->
|
||||
<item>?android:attr/candidatesTextStyleSpans</item>
|
||||
<item>@android:string/unknownName</item> <!-- value = Unknown -->
|
||||
</string-array>
|
||||
|
||||
<!-- resources that the above array can refer to -->
|
||||
<integer name="ten">10</integer>
|
||||
<integer name="twelve">12</integer>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<attr name="myattr" format="integer" />
|
||||
</resources>
|
||||
@@ -1,7 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
||||
<item name="myattr">@integer/ten</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
|
||||
@@ -296,6 +296,11 @@ public class Main {
|
||||
renderAndVerify("allwidgets.xml", "allwidgets.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayCheck() throws ClassNotFoundException {
|
||||
renderAndVerify("array_check.xml", "array_check.png");
|
||||
}
|
||||
|
||||
/** Test expand_layout.xml */
|
||||
@Test
|
||||
public void testExpand() throws ClassNotFoundException {
|
||||
@@ -388,7 +393,6 @@ public class Main {
|
||||
ResourceResolver.create(mProjectResources.getConfiguredResources(config),
|
||||
mFrameworkRepo.getConfiguredResources(config),
|
||||
themeName, false);
|
||||
|
||||
return new SessionParams(
|
||||
layoutParser,
|
||||
renderingMode,
|
||||
|
||||
Reference in New Issue
Block a user