1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.res; 18 19 import android.graphics.drawable.Drawable; 20 import android.util.AttributeSet; 21 import android.util.DisplayMetrics; 22 import android.util.Log; 23 import android.util.TypedValue; 24 25 import com.android.internal.util.XmlUtils; 26 27 import java.util.Arrays; 28 29 /** 30 * Container for an array of values that were retrieved with 31 * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)} 32 * or {@link Resources#obtainAttributes}. Be 33 * sure to call {@link #recycle} when done with them. 34 * 35 * The indices used to retrieve values from this structure correspond to 36 * the positions of the attributes given to obtainStyledAttributes. 37 */ 38 public class TypedArray { 39 private final Resources mResources; 40 /*package*/ XmlBlock.Parser mXml; 41 /*package*/ int[] mRsrcs; 42 /*package*/ int[] mData; 43 /*package*/ int[] mIndices; 44 /*package*/ int mLength; 45 private TypedValue mValue = new TypedValue(); 46 47 /** 48 * Return the number of values in this array. 49 */ 50 public int length() { 51 return mLength; 52 } 53 54 /** 55 * Return the number of indices in the array that actually have data. 56 */ 57 public int getIndexCount() { 58 return mIndices[0]; 59 } 60 61 /** 62 * Return an index in the array that has data. 63 * 64 * @param at The index you would like to returned, ranging from 0 to 65 * {@link #getIndexCount()}. 66 * 67 * @return The index at the given offset, which can be used with 68 * {@link #getValue} and related APIs. 69 */ 70 public int getIndex(int at) { 71 return mIndices[1+at]; 72 } 73 74 /** 75 * Return the Resources object this array was loaded from. 76 */ 77 public Resources getResources() { 78 return mResources; 79 } 80 81 /** 82 * Retrieve the styled string value for the attribute at <var>index</var>. 83 * 84 * @param index Index of attribute to retrieve. 85 * 86 * @return CharSequence holding string data. May be styled. Returns 87 * null if the attribute is not defined. 88 */ 89 public CharSequence getText(int index) { 90 index *= AssetManager.STYLE_NUM_ENTRIES; 91 final int[] data = mData; 92 final int type = data[index+AssetManager.STYLE_TYPE]; 93 if (type == TypedValue.TYPE_NULL) { 94 return null; 95 } else if (type == TypedValue.TYPE_STRING) { 96 return loadStringValueAt(index); 97 } 98 99 TypedValue v = mValue; 100 if (getValueAt(index, v)) { 101 Log.w(Resources.TAG, "Converting to string: " + v); 102 return v.coerceToString(); 103 } 104 Log.w(Resources.TAG, "getString of bad type: 0x" 105 + Integer.toHexString(type)); 106 return null; 107 } 108 109 /** 110 * Retrieve the string value for the attribute at <var>index</var>. 111 * 112 * @param index Index of attribute to retrieve. 113 * 114 * @return String holding string data. Any styling information is 115 * removed. Returns null if the attribute is not defined. 116 */ 117 public String getString(int index) { 118 index *= AssetManager.STYLE_NUM_ENTRIES; 119 final int[] data = mData; 120 final int type = data[index+AssetManager.STYLE_TYPE]; 121 if (type == TypedValue.TYPE_NULL) { 122 return null; 123 } else if (type == TypedValue.TYPE_STRING) { 124 return loadStringValueAt(index).toString(); 125 } 126 127 TypedValue v = mValue; 128 if (getValueAt(index, v)) { 129 Log.w(Resources.TAG, "Converting to string: " + v); 130 CharSequence cs = v.coerceToString(); 131 return cs != null ? cs.toString() : null; 132 } 133 Log.w(Resources.TAG, "getString of bad type: 0x" 134 + Integer.toHexString(type)); 135 return null; 136 } 137 138 /** 139 * Retrieve the string value for the attribute at <var>index</var>, but 140 * only if that string comes from an immediate value in an XML file. That 141 * is, this does not allow references to string resources, string 142 * attributes, or conversions from other types. As such, this method 143 * will only return strings for TypedArray objects that come from 144 * attributes in an XML file. 145 * 146 * @param index Index of attribute to retrieve. 147 * 148 * @return String holding string data. Any styling information is 149 * removed. Returns null if the attribute is not defined or is not 150 * an immediate string value. 151 */ 152 public String getNonResourceString(int index) { 153 index *= AssetManager.STYLE_NUM_ENTRIES; 154 final int[] data = mData; 155 final int type = data[index+AssetManager.STYLE_TYPE]; 156 if (type == TypedValue.TYPE_STRING) { 157 final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 158 if (cookie < 0) { 159 return mXml.getPooledString( 160 data[index+AssetManager.STYLE_DATA]).toString(); 161 } 162 } 163 return null; 164 } 165 166 /** 167 * @hide 168 * Retrieve the string value for the attribute at <var>index</var> that is 169 * not allowed to change with the given configurations. 170 * 171 * @param index Index of attribute to retrieve. 172 * @param allowedChangingConfigs Bit mask of configurations from 173 * ActivityInfo that are allowed to change. 174 * 175 * @return String holding string data. Any styling information is 176 * removed. Returns null if the attribute is not defined. 177 */ 178 public String getNonConfigurationString(int index, int allowedChangingConfigs) { 179 index *= AssetManager.STYLE_NUM_ENTRIES; 180 final int[] data = mData; 181 final int type = data[index+AssetManager.STYLE_TYPE]; 182 if ((data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]&~allowedChangingConfigs) != 0) { 183 return null; 184 } 185 if (type == TypedValue.TYPE_NULL) { 186 return null; 187 } else if (type == TypedValue.TYPE_STRING) { 188 return loadStringValueAt(index).toString(); 189 } 190 191 TypedValue v = mValue; 192 if (getValueAt(index, v)) { 193 Log.w(Resources.TAG, "Converting to string: " + v); 194 CharSequence cs = v.coerceToString(); 195 return cs != null ? cs.toString() : null; 196 } 197 Log.w(Resources.TAG, "getString of bad type: 0x" 198 + Integer.toHexString(type)); 199 return null; 200 } 201 202 /** 203 * Retrieve the boolean value for the attribute at <var>index</var>. 204 * 205 * @param index Index of attribute to retrieve. 206 * @param defValue Value to return if the attribute is not defined. 207 * 208 * @return Attribute boolean value, or defValue if not defined. 209 */ 210 public boolean getBoolean(int index, boolean defValue) { 211 index *= AssetManager.STYLE_NUM_ENTRIES; 212 final int[] data = mData; 213 final int type = data[index+AssetManager.STYLE_TYPE]; 214 if (type == TypedValue.TYPE_NULL) { 215 return defValue; 216 } else if (type >= TypedValue.TYPE_FIRST_INT 217 && type <= TypedValue.TYPE_LAST_INT) { 218 return data[index+AssetManager.STYLE_DATA] != 0; 219 } 220 221 TypedValue v = mValue; 222 if (getValueAt(index, v)) { 223 Log.w(Resources.TAG, "Converting to boolean: " + v); 224 return XmlUtils.convertValueToBoolean( 225 v.coerceToString(), defValue); 226 } 227 Log.w(Resources.TAG, "getBoolean of bad type: 0x" 228 + Integer.toHexString(type)); 229 return defValue; 230 } 231 232 /** 233 * Retrieve the integer value for the attribute at <var>index</var>. 234 * 235 * @param index Index of attribute to retrieve. 236 * @param defValue Value to return if the attribute is not defined. 237 * 238 * @return Attribute int value, or defValue if not defined. 239 */ 240 public int getInt(int index, int defValue) { 241 index *= AssetManager.STYLE_NUM_ENTRIES; 242 final int[] data = mData; 243 final int type = data[index+AssetManager.STYLE_TYPE]; 244 if (type == TypedValue.TYPE_NULL) { 245 return defValue; 246 } else if (type >= TypedValue.TYPE_FIRST_INT 247 && type <= TypedValue.TYPE_LAST_INT) { 248 return data[index+AssetManager.STYLE_DATA]; 249 } 250 251 TypedValue v = mValue; 252 if (getValueAt(index, v)) { 253 Log.w(Resources.TAG, "Converting to int: " + v); 254 return XmlUtils.convertValueToInt( 255 v.coerceToString(), defValue); 256 } 257 Log.w(Resources.TAG, "getInt of bad type: 0x" 258 + Integer.toHexString(type)); 259 return defValue; 260 } 261 262 /** 263 * Retrieve the float value for the attribute at <var>index</var>. 264 * 265 * @param index Index of attribute to retrieve. 266 * 267 * @return Attribute float value, or defValue if not defined.. 268 */ 269 public float getFloat(int index, float defValue) { 270 index *= AssetManager.STYLE_NUM_ENTRIES; 271 final int[] data = mData; 272 final int type = data[index+AssetManager.STYLE_TYPE]; 273 if (type == TypedValue.TYPE_NULL) { 274 return defValue; 275 } else if (type == TypedValue.TYPE_FLOAT) { 276 return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]); 277 } else if (type >= TypedValue.TYPE_FIRST_INT 278 && type <= TypedValue.TYPE_LAST_INT) { 279 return data[index+AssetManager.STYLE_DATA]; 280 } 281 282 TypedValue v = mValue; 283 if (getValueAt(index, v)) { 284 Log.w(Resources.TAG, "Converting to float: " + v); 285 CharSequence str = v.coerceToString(); 286 if (str != null) { 287 return Float.parseFloat(str.toString()); 288 } 289 } 290 Log.w(Resources.TAG, "getFloat of bad type: 0x" 291 + Integer.toHexString(type)); 292 return defValue; 293 } 294 295 /** 296 * Retrieve the color value for the attribute at <var>index</var>. If 297 * the attribute references a color resource holding a complex 298 * {@link android.content.res.ColorStateList}, then the default color from 299 * the set is returned. 300 * 301 * @param index Index of attribute to retrieve. 302 * @param defValue Value to return if the attribute is not defined or 303 * not a resource. 304 * 305 * @return Attribute color value, or defValue if not defined. 306 */ 307 public int getColor(int index, int defValue) { 308 index *= AssetManager.STYLE_NUM_ENTRIES; 309 final int[] data = mData; 310 final int type = data[index+AssetManager.STYLE_TYPE]; 311 if (type == TypedValue.TYPE_NULL) { 312 return defValue; 313 } else if (type >= TypedValue.TYPE_FIRST_INT 314 && type <= TypedValue.TYPE_LAST_INT) { 315 return data[index+AssetManager.STYLE_DATA]; 316 } else if (type == TypedValue.TYPE_STRING) { 317 final TypedValue value = mValue; 318 if (getValueAt(index, value)) { 319 ColorStateList csl = mResources.loadColorStateList( 320 value, value.resourceId); 321 return csl.getDefaultColor(); 322 } 323 return defValue; 324 } 325 326 throw new UnsupportedOperationException("Can't convert to color: type=0x" 327 + Integer.toHexString(type)); 328 } 329 330 /** 331 * Retrieve the ColorStateList for the attribute at <var>index</var>. 332 * The value may be either a single solid color or a reference to 333 * a color or complex {@link android.content.res.ColorStateList} description. 334 * 335 * @param index Index of attribute to retrieve. 336 * 337 * @return ColorStateList for the attribute, or null if not defined. 338 */ 339 public ColorStateList getColorStateList(int index) { 340 final TypedValue value = mValue; 341 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 342 return mResources.loadColorStateList(value, value.resourceId); 343 } 344 return null; 345 } 346 347 /** 348 * Retrieve the integer value for the attribute at <var>index</var>. 349 * 350 * @param index Index of attribute to retrieve. 351 * @param defValue Value to return if the attribute is not defined or 352 * not a resource. 353 * 354 * @return Attribute integer value, or defValue if not defined. 355 */ 356 public int getInteger(int index, int defValue) { 357 index *= AssetManager.STYLE_NUM_ENTRIES; 358 final int[] data = mData; 359 final int type = data[index+AssetManager.STYLE_TYPE]; 360 if (type == TypedValue.TYPE_NULL) { 361 return defValue; 362 } else if (type >= TypedValue.TYPE_FIRST_INT 363 && type <= TypedValue.TYPE_LAST_INT) { 364 return data[index+AssetManager.STYLE_DATA]; 365 } 366 367 throw new UnsupportedOperationException("Can't convert to integer: type=0x" 368 + Integer.toHexString(type)); 369 } 370 371 /** 372 * Retrieve a dimensional unit attribute at <var>index</var>. Unit 373 * conversions are based on the current {@link DisplayMetrics} 374 * associated with the resources this {@link TypedArray} object 375 * came from. 376 * 377 * @param index Index of attribute to retrieve. 378 * @param defValue Value to return if the attribute is not defined or 379 * not a resource. 380 * 381 * @return Attribute dimension value multiplied by the appropriate 382 * metric, or defValue if not defined. 383 * 384 * @see #getDimensionPixelOffset 385 * @see #getDimensionPixelSize 386 */ 387 public float getDimension(int index, float defValue) { 388 index *= AssetManager.STYLE_NUM_ENTRIES; 389 final int[] data = mData; 390 final int type = data[index+AssetManager.STYLE_TYPE]; 391 if (type == TypedValue.TYPE_NULL) { 392 return defValue; 393 } else if (type == TypedValue.TYPE_DIMENSION) { 394 return TypedValue.complexToDimension( 395 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 396 } 397 398 throw new UnsupportedOperationException("Can't convert to dimension: type=0x" 399 + Integer.toHexString(type)); 400 } 401 402 /** 403 * Retrieve a dimensional unit attribute at <var>index</var> for use 404 * as an offset in raw pixels. This is the same as 405 * {@link #getDimension}, except the returned value is converted to 406 * integer pixels for you. An offset conversion involves simply 407 * truncating the base value to an integer. 408 * 409 * @param index Index of attribute to retrieve. 410 * @param defValue Value to return if the attribute is not defined or 411 * not a resource. 412 * 413 * @return Attribute dimension value multiplied by the appropriate 414 * metric and truncated to integer pixels, or defValue if not defined. 415 * 416 * @see #getDimension 417 * @see #getDimensionPixelSize 418 */ 419 public int getDimensionPixelOffset(int index, int defValue) { 420 index *= AssetManager.STYLE_NUM_ENTRIES; 421 final int[] data = mData; 422 final int type = data[index+AssetManager.STYLE_TYPE]; 423 if (type == TypedValue.TYPE_NULL) { 424 return defValue; 425 } else if (type == TypedValue.TYPE_DIMENSION) { 426 return TypedValue.complexToDimensionPixelOffset( 427 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 428 } 429 430 throw new UnsupportedOperationException("Can't convert to dimension: type=0x" 431 + Integer.toHexString(type)); 432 } 433 434 /** 435 * Retrieve a dimensional unit attribute at <var>index</var> for use 436 * as a size in raw pixels. This is the same as 437 * {@link #getDimension}, except the returned value is converted to 438 * integer pixels for use as a size. A size conversion involves 439 * rounding the base value, and ensuring that a non-zero base value 440 * is at least one pixel in size. 441 * 442 * @param index Index of attribute to retrieve. 443 * @param defValue Value to return if the attribute is not defined or 444 * not a resource. 445 * 446 * @return Attribute dimension value multiplied by the appropriate 447 * metric and truncated to integer pixels, or defValue if not defined. 448 * 449 * @see #getDimension 450 * @see #getDimensionPixelOffset 451 */ 452 public int getDimensionPixelSize(int index, int defValue) { 453 index *= AssetManager.STYLE_NUM_ENTRIES; 454 final int[] data = mData; 455 final int type = data[index+AssetManager.STYLE_TYPE]; 456 if (type == TypedValue.TYPE_NULL) { 457 return defValue; 458 } else if (type == TypedValue.TYPE_DIMENSION) { 459 return TypedValue.complexToDimensionPixelSize( 460 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 461 } 462 463 throw new UnsupportedOperationException("Can't convert to dimension: type=0x" 464 + Integer.toHexString(type)); 465 } 466 467 /** 468 * Special version of {@link #getDimensionPixelSize} for retrieving 469 * {@link android.view.ViewGroup}'s layout_width and layout_height 470 * attributes. This is only here for performance reasons; applications 471 * should use {@link #getDimensionPixelSize}. 472 * 473 * @param index Index of the attribute to retrieve. 474 * @param name Textual name of attribute for error reporting. 475 * 476 * @return Attribute dimension value multiplied by the appropriate 477 * metric and truncated to integer pixels. 478 */ 479 public int getLayoutDimension(int index, String name) { 480 index *= AssetManager.STYLE_NUM_ENTRIES; 481 final int[] data = mData; 482 final int type = data[index+AssetManager.STYLE_TYPE]; 483 if (type >= TypedValue.TYPE_FIRST_INT 484 && type <= TypedValue.TYPE_LAST_INT) { 485 return data[index+AssetManager.STYLE_DATA]; 486 } else if (type == TypedValue.TYPE_DIMENSION) { 487 return TypedValue.complexToDimensionPixelSize( 488 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 489 } 490 491 throw new RuntimeException(getPositionDescription() 492 + ": You must supply a " + name + " attribute."); 493 } 494 495 /** 496 * Special version of {@link #getDimensionPixelSize} for retrieving 497 * {@link android.view.ViewGroup}'s layout_width and layout_height 498 * attributes. This is only here for performance reasons; applications 499 * should use {@link #getDimensionPixelSize}. 500 * 501 * @param index Index of the attribute to retrieve. 502 * @param defValue The default value to return if this attribute is not 503 * default or contains the wrong type of data. 504 * 505 * @return Attribute dimension value multiplied by the appropriate 506 * metric and truncated to integer pixels. 507 */ 508 public int getLayoutDimension(int index, int defValue) { 509 index *= AssetManager.STYLE_NUM_ENTRIES; 510 final int[] data = mData; 511 final int type = data[index+AssetManager.STYLE_TYPE]; 512 if (type >= TypedValue.TYPE_FIRST_INT 513 && type <= TypedValue.TYPE_LAST_INT) { 514 return data[index+AssetManager.STYLE_DATA]; 515 } else if (type == TypedValue.TYPE_DIMENSION) { 516 return TypedValue.complexToDimensionPixelSize( 517 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 518 } 519 520 return defValue; 521 } 522 523 /** 524 * Retrieve a fractional unit attribute at <var>index</var>. 525 * 526 * @param index Index of attribute to retrieve. 527 * @param base The base value of this fraction. In other words, a 528 * standard fraction is multiplied by this value. 529 * @param pbase The parent base value of this fraction. In other 530 * words, a parent fraction (nn%p) is multiplied by this 531 * value. 532 * @param defValue Value to return if the attribute is not defined or 533 * not a resource. 534 * 535 * @return Attribute fractional value multiplied by the appropriate 536 * base value, or defValue if not defined. 537 */ 538 public float getFraction(int index, int base, int pbase, float defValue) { 539 index *= AssetManager.STYLE_NUM_ENTRIES; 540 final int[] data = mData; 541 final int type = data[index+AssetManager.STYLE_TYPE]; 542 if (type == TypedValue.TYPE_NULL) { 543 return defValue; 544 } else if (type == TypedValue.TYPE_FRACTION) { 545 return TypedValue.complexToFraction( 546 data[index+AssetManager.STYLE_DATA], base, pbase); 547 } 548 549 throw new UnsupportedOperationException("Can't convert to fraction: type=0x" 550 + Integer.toHexString(type)); 551 } 552 553 /** 554 * Retrieve the resource identifier for the attribute at 555 * <var>index</var>. Note that attribute resource as resolved when 556 * the overall {@link TypedArray} object is retrieved. As a 557 * result, this function will return the resource identifier of the 558 * final resource value that was found, <em>not</em> necessarily the 559 * original resource that was specified by the attribute. 560 * 561 * @param index Index of attribute to retrieve. 562 * @param defValue Value to return if the attribute is not defined or 563 * not a resource. 564 * 565 * @return Attribute resource identifier, or defValue if not defined. 566 */ 567 public int getResourceId(int index, int defValue) { 568 index *= AssetManager.STYLE_NUM_ENTRIES; 569 final int[] data = mData; 570 if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) { 571 final int resid = data[index+AssetManager.STYLE_RESOURCE_ID]; 572 if (resid != 0) { 573 return resid; 574 } 575 } 576 return defValue; 577 } 578 579 /** 580 * Retrieve the Drawable for the attribute at <var>index</var>. This 581 * gets the resource ID of the selected attribute, and uses 582 * {@link Resources#getDrawable Resources.getDrawable} of the owning 583 * Resources object to retrieve its Drawable. 584 * 585 * @param index Index of attribute to retrieve. 586 * 587 * @return Drawable for the attribute, or null if not defined. 588 */ 589 public Drawable getDrawable(int index) { 590 final TypedValue value = mValue; 591 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 592 if (false) { 593 System.out.println("******************************************************************"); 594 System.out.println("Got drawable resource: type=" 595 + value.type 596 + " str=" + value.string 597 + " int=0x" + Integer.toHexString(value.data) 598 + " cookie=" + value.assetCookie); 599 System.out.println("******************************************************************"); 600 } 601 return mResources.loadDrawable(value, value.resourceId); 602 } 603 return null; 604 } 605 606 /** 607 * Retrieve the CharSequence[] for the attribute at <var>index</var>. 608 * This gets the resource ID of the selected attribute, and uses 609 * {@link Resources#getTextArray Resources.getTextArray} of the owning 610 * Resources object to retrieve its String[]. 611 * 612 * @param index Index of attribute to retrieve. 613 * 614 * @return CharSequence[] for the attribute, or null if not defined. 615 */ 616 public CharSequence[] getTextArray(int index) { 617 final TypedValue value = mValue; 618 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 619 if (false) { 620 System.out.println("******************************************************************"); 621 System.out.println("Got drawable resource: type=" 622 + value.type 623 + " str=" + value.string 624 + " int=0x" + Integer.toHexString(value.data) 625 + " cookie=" + value.assetCookie); 626 System.out.println("******************************************************************"); 627 } 628 return mResources.getTextArray(value.resourceId); 629 } 630 return null; 631 } 632 633 /** 634 * Retrieve the raw TypedValue for the attribute at <var>index</var>. 635 * 636 * @param index Index of attribute to retrieve. 637 * @param outValue TypedValue object in which to place the attribute's 638 * data. 639 * 640 * @return Returns true if the value was retrieved, else false. 641 */ 642 public boolean getValue(int index, TypedValue outValue) { 643 return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue); 644 } 645 646 /** 647 * Determines whether there is an attribute at <var>index</var>. 648 * 649 * @param index Index of attribute to retrieve. 650 * 651 * @return True if the attribute has a value, false otherwise. 652 */ 653 public boolean hasValue(int index) { 654 index *= AssetManager.STYLE_NUM_ENTRIES; 655 final int[] data = mData; 656 final int type = data[index+AssetManager.STYLE_TYPE]; 657 return type != TypedValue.TYPE_NULL; 658 } 659 660 /** 661 * Retrieve the raw TypedValue for the attribute at <var>index</var> 662 * and return a temporary object holding its data. This object is only 663 * valid until the next call on to {@link TypedArray}. 664 * 665 * @param index Index of attribute to retrieve. 666 * 667 * @return Returns a TypedValue object if the attribute is defined, 668 * containing its data; otherwise returns null. (You will not 669 * receive a TypedValue whose type is TYPE_NULL.) 670 */ 671 public TypedValue peekValue(int index) { 672 final TypedValue value = mValue; 673 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 674 return value; 675 } 676 return null; 677 } 678 679 /** 680 * Returns a message about the parser state suitable for printing error messages. 681 */ 682 public String getPositionDescription() { 683 return mXml != null ? mXml.getPositionDescription() : "<internal>"; 684 } 685 686 /** 687 * Give back a previously retrieved StyledAttributes, for later re-use. 688 */ 689 public void recycle() { 690 synchronized (mResources.mTmpValue) { 691 TypedArray cached = mResources.mCachedStyledAttributes; 692 if (cached == null || cached.mData.length < mData.length) { 693 mXml = null; 694 mResources.mCachedStyledAttributes = this; 695 } 696 } 697 } 698 699 private boolean getValueAt(int index, TypedValue outValue) { 700 final int[] data = mData; 701 final int type = data[index+AssetManager.STYLE_TYPE]; 702 if (type == TypedValue.TYPE_NULL) { 703 return false; 704 } 705 outValue.type = type; 706 outValue.data = data[index+AssetManager.STYLE_DATA]; 707 outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 708 outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID]; 709 outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]; 710 outValue.density = data[index+AssetManager.STYLE_DENSITY]; 711 outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null; 712 return true; 713 } 714 715 private CharSequence loadStringValueAt(int index) { 716 final int[] data = mData; 717 final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 718 if (cookie < 0) { 719 if (mXml != null) { 720 return mXml.getPooledString( 721 data[index+AssetManager.STYLE_DATA]); 722 } 723 return null; 724 } 725 //System.out.println("Getting pooled from: " + v); 726 return mResources.mAssets.getPooledString( 727 cookie, data[index+AssetManager.STYLE_DATA]); 728 } 729 730 /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) { 731 mResources = resources; 732 mData = data; 733 mIndices = indices; 734 mLength = len; 735 } 736 737 public String toString() { 738 return Arrays.toString(mData); 739 } 740 } 741