ResourceHelper.java revision 458f2a7bbbcc45d12b575fe9f3b2f8e1a20f9b1c
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2008 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.DensityBasedResourceValue; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.LayoutLog; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.ResourceValue; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.Bridge; 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeContext; 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ninepatch.NinePatch; 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ninepatch.NinePatchChunk; 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.Density; 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParser; 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException; 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.res.ColorStateList; 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap; 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap_Delegate; 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.NinePatch_Delegate; 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Rect; 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.BitmapDrawable; 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.ColorDrawable; 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.Drawable; 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.NinePatchDrawable; 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.TypedValue; 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.File; 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.FileInputStream; 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.IOException; 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.InputStream; 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.net.MalformedURLException; 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.regex.Matcher; 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.regex.Pattern; 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Helper class to provide various conversion method used in handling android resources. 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic final class ResourceHelper { 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final static Pattern sFloatPattern = Pattern.compile("(-?[0-9]+(?:\\.[0-9]+)?)(.*)"); 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final static float[] sFloatOut = new float[1]; 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final static TypedValue mValue = new TypedValue(); 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns the color value represented by the given string value 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param value the color value 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return the color as an int 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @throw NumberFormatException if the conversion failed. 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static int getColor(String value) { 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value != null) { 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value.startsWith("#") == false) { 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throw new NumberFormatException( 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String.format("Color value '%s' must start with #", value)); 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = value.substring(1); 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // make sure it's not longer than 32bit 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value.length() > 8) { 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throw new NumberFormatException(String.format( 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Color value '%s' is too long. Format is either" + 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "#AARRGGBB, #RRGGBB, #RGB, or #ARGB", 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value)); 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value.length() == 3) { // RGB format 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski char[] color = new char[8]; 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[0] = color[1] = 'F'; 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[2] = color[3] = value.charAt(0); 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[4] = color[5] = value.charAt(1); 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[6] = color[7] = value.charAt(2); 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = new String(color); 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (value.length() == 4) { // ARGB format 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski char[] color = new char[8]; 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[0] = color[1] = value.charAt(0); 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[2] = color[3] = value.charAt(1); 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[4] = color[5] = value.charAt(2); 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski color[6] = color[7] = value.charAt(3); 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = new String(color); 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (value.length() == 6) { 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = "FF" + value; 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // this is a RRGGBB or AARRGGBB value 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Integer.parseInt will fail to parse strings like "ff191919", so we use 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // a Long, but cast the result back into an int, since we know that we're only 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // dealing with 32 bit values. 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return (int)Long.parseLong(value, 16); 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throw new NumberFormatException(); 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) { 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String value = resValue.getValue(); 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value != null && RenderResources.REFERENCE_NULL.equals(value) == false) { 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // first check if the value is a file (xml most likely) 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski File f = new File(value); 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (f.isFile()) { 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // let the framework inflate the ColorStateList from the XML file, by 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // providing an XmlPullParser 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski XmlPullParser parser = ParserFactory.create(f); 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser, context, resValue.isFramework()); 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return ColorStateList.createFromXml(context.getResources(), blockParser); 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } finally { 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski blockParser.ensurePopped(); 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (XmlPullParserException e) { 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_BROKEN, 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed to configure parser for " + value, e, null /*data*/); 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // we'll return null below. 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (Exception e) { 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // this is an error and not warning since the file existence is 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // checked before attempting to parse it. 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ, 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed to parse file " + value, e, null /*data*/); 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // try to load the color state list from an int 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int color = ResourceHelper.getColor(value); 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return ColorStateList.valueOf(color); 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (NumberFormatException e) { 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed to convert " + value + " into a ColorStateList", e, 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski null /*data*/); 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns a drawable from the given value. 163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable, 164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * or an hexadecimal color 165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param context the current context 166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static Drawable getDrawable(ResourceValue value, BridgeContext context) { 16814bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta if (value == null) { 16914bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta return null; 17014bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta } 171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String stringValue = value.getValue(); 172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (RenderResources.REFERENCE_NULL.equals(stringValue)) { 173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String lowerCaseValue = stringValue.toLowerCase(); 177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Density density = Density.MEDIUM; 179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (value instanceof DensityBasedResourceValue) { 180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski density = 181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ((DensityBasedResourceValue)value).getResourceDensity(); 182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) { 186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski File file = new File(stringValue); 187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (file.isFile()) { 188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return getNinePatchDrawable( 190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new FileInputStream(file), density, value.isFramework(), 191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stringValue, context); 192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (IOException e) { 193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // failed to read the file, we'll return null below. 194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ, 195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed lot load " + file.getAbsolutePath(), e, null /*data*/); 196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (lowerCaseValue.endsWith(".xml")) { 201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // create a block parser for the file 202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski File f = new File(stringValue); 203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (f.isFile()) { 204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // let the framework inflate the Drawable from the XML file. 206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski XmlPullParser parser = ParserFactory.create(f); 207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( 209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser, context, value.isFramework()); 210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return Drawable.createFromXml(context.getResources(), blockParser); 212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } finally { 213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski blockParser.ensurePopped(); 214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (Exception e) { 216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // this is an error and not warning since the file existence is checked before 217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // attempting to parse it. 218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(null, "Failed to parse file " + stringValue, 219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski e, null /*data*/); 220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_BROKEN, 223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String.format("File %s does not exist (or is not a file)", stringValue), 224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski null /*data*/); 225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski File bmpFile = new File(stringValue); 230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bmpFile.isFile()) { 231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bitmap bitmap = Bridge.getCachedBitmap(stringValue, 233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value.isFramework() ? null : context.getProjectKey()); 234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bitmap == null) { 236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bitmap = Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/, 237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski density); 238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.setCachedBitmap(stringValue, bitmap, 239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value.isFramework() ? null : context.getProjectKey()); 240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return new BitmapDrawable(context.getResources(), bitmap); 243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (IOException e) { 244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // we'll return null below 245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ, 246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed lot load " + bmpFile.getAbsolutePath(), e, null /*data*/); 247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // attempt to get a color from the value 250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int color = getColor(stringValue); 252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return new ColorDrawable(color); 253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (NumberFormatException e) { 254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // we'll return null below. 255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, 256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Failed to convert " + stringValue + " into a drawable", e, 257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski null /*data*/); 258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static Drawable getNinePatchDrawable(InputStream inputStream, Density density, 266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean isFramework, String cacheKey, BridgeContext context) throws IOException { 267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // see if we still have both the chunk and the bitmap in the caches 268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski NinePatchChunk chunk = Bridge.getCached9Patch(cacheKey, 269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski isFramework ? null : context.getProjectKey()); 270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bitmap bitmap = Bridge.getCachedBitmap(cacheKey, 271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski isFramework ? null : context.getProjectKey()); 272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // if either chunk or bitmap is null, then we reload the 9-patch file. 274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (chunk == null || bitmap == null) { 275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski NinePatch ninePatch = NinePatch.load(inputStream, true /*is9Patch*/, 277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski false /* convert */); 278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (ninePatch != null) { 279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (chunk == null) { 280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski chunk = ninePatch.getChunk(); 281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.setCached9Patch(cacheKey, chunk, 283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski isFramework ? null : context.getProjectKey()); 284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bitmap == null) { 287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bitmap = Bitmap_Delegate.createBitmap(ninePatch.getImage(), 288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski false /*isMutable*/, 289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski density); 290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.setCachedBitmap(cacheKey, bitmap, 292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski isFramework ? null : context.getProjectKey()); 293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (MalformedURLException e) { 296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // URL is wrong, we'll return null below 297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (chunk != null && bitmap != null) { 301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int[] padding = chunk.getPadding(); 302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Rect paddingRect = new Rect(padding[0], padding[1], padding[2], padding[3]); 303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return new NinePatchDrawable(context.getResources(), bitmap, 305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski NinePatch_Delegate.serialize(chunk), 306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski paddingRect, null); 307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ------- TypedValue stuff 313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // This is taken from //device/libs/utils/ResourceTypes.cpp 314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static final class UnitEntry { 316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String name; 317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int type; 318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int unit; 319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski float scale; 320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski UnitEntry(String name, int type, int unit, float scale) { 322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.name = name; 323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.type = type; 324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.unit = unit; 325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.scale = scale; 326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final static UnitEntry[] sUnitNames = new UnitEntry[] { 330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("px", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_PX, 1.0f), 331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("dip", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_DIP, 1.0f), 332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("dp", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_DIP, 1.0f), 333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("sp", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_SP, 1.0f), 334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("pt", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_PT, 1.0f), 335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("in", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_IN, 1.0f), 336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("mm", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_MM, 1.0f), 337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("%", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION, 1.0f/100), 338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new UnitEntry("%p", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100), 339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski }; 340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns the raw value from the given attribute float-type value string. 343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This object is only valid until the next call on to {@link ResourceHelper}. 344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static TypedValue getValue(String attribute, String value, boolean requireUnit) { 346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (parseFloatAttribute(attribute, value, mValue, requireUnit)) { 347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return mValue; 348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Parse a float attribute and return the parsed value into a given TypedValue. 355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param attribute the name of the attribute. Can be null if <var>requireUnit</var> is false. 356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param value the string value of the attribute 357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param outValue the TypedValue to receive the parsed value 358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param requireUnit whether the value is expected to contain a unit. 359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return true if success. 360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static boolean parseFloatAttribute(String attribute, String value, 362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski TypedValue outValue, boolean requireUnit) { 363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski assert requireUnit == false || attribute != null; 364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // remove the space before and after 366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = value.trim(); 367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int len = value.length(); 368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (len <= 0) { 370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check that there's no non ascii characters. 374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski char[] buf = value.toCharArray(); 375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (int i = 0 ; i < len ; i++) { 376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (buf[i] > 255) { 377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check the first character 382458f2a7bbbcc45d12b575fe9f3b2f8e1a20f9b1cDeepanshu Gupta if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') { 383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // now look for the string that is after the float... 387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Matcher m = sFloatPattern.matcher(value); 388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (m.matches()) { 389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String f_str = m.group(1); 390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String end = m.group(2); 391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski float f; 393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski f = Float.parseFloat(f_str); 395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (NumberFormatException e) { 396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // this shouldn't happen with the regexp above. 397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (end.length() > 0 && end.charAt(0) != ' ') { 401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Might be a unit... 402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (parseUnit(end, outValue, sFloatOut)) { 403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski computeTypedValue(outValue, f, sFloatOut[0]); 404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // make sure it's only spaces at the end. 410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski end = end.trim(); 411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (end.length() == 0) { 413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (outValue != null) { 414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (requireUnit == false) { 415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outValue.type = TypedValue.TYPE_FLOAT; 416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outValue.data = Float.floatToIntBits(f); 417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // no unit when required? Use dp and out an error. 419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski applyUnit(sUnitNames[1], outValue, sFloatOut); 420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski computeTypedValue(outValue, f, sFloatOut[0]); 421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE, 423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String.format( 424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "Dimension \"%1$s\" in attribute \"%2$s\" is missing unit!", 425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value, attribute), 426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski null); 427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static void computeTypedValue(TypedValue outValue, float value, float scale) { 437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value *= scale; 438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean neg = value < 0; 439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (neg) { 440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski value = -value; 441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski long bits = (long)(value*(1<<23)+.5f); 443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int radix; 444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int shift; 445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if ((bits&0x7fffff) == 0) { 446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Always use 23p0 if there is no fraction, just to make 447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // things easier to read. 448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski radix = TypedValue.COMPLEX_RADIX_23p0; 449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shift = 23; 450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if ((bits&0xffffffffff800000L) == 0) { 451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Magnitude is zero -- can fit in 0 bits of precision. 452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski radix = TypedValue.COMPLEX_RADIX_0p23; 453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shift = 0; 454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if ((bits&0xffffffff80000000L) == 0) { 455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Magnitude can fit in 8 bits of precision. 456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski radix = TypedValue.COMPLEX_RADIX_8p15; 457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shift = 8; 458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if ((bits&0xffffff8000000000L) == 0) { 459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Magnitude can fit in 16 bits of precision. 460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski radix = TypedValue.COMPLEX_RADIX_16p7; 461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shift = 16; 462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Magnitude needs entire range, so no fractional part. 464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski radix = TypedValue.COMPLEX_RADIX_23p0; 465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shift = 23; 466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int mantissa = (int)( 468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK); 469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (neg) { 470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK; 471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outValue.data |= 473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski (radix<<TypedValue.COMPLEX_RADIX_SHIFT) 474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT); 475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static boolean parseUnit(String str, TypedValue outValue, float[] outScale) { 478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski str = str.trim(); 479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (UnitEntry unit : sUnitNames) { 481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (unit.name.equals(str)) { 482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski applyUnit(unit, outValue, outScale); 483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static void applyUnit(UnitEntry unit, TypedValue outValue, float[] outScale) { 491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outValue.type = unit.type; 492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT; 493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outScale[0] = unit.scale; 494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 497