TypedArray.java revision 6868d6f349610c15256471cc3d5fa708cbfd5f1d
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 17package android.content.res; 18 19import android.graphics.drawable.Drawable; 20import android.util.AttributeSet; 21import android.util.DisplayMetrics; 22import android.util.Log; 23import android.util.TypedValue; 24 25import com.android.internal.util.XmlUtils; 26 27import 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 */ 38public 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 /*package*/ 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 * @throws RuntimeException 480 * if this TypedArray does not contain an entry for <code>index</code> 481 * 482 * @deprecated Use {@link #getLayoutDimension(int, int)} instead. 483 * 484 */ 485 @Deprecated 486 public int getLayoutDimension(int index, String name) { 487 index *= AssetManager.STYLE_NUM_ENTRIES; 488 final int[] data = mData; 489 final int type = data[index+AssetManager.STYLE_TYPE]; 490 if (type >= TypedValue.TYPE_FIRST_INT 491 && type <= TypedValue.TYPE_LAST_INT) { 492 return data[index+AssetManager.STYLE_DATA]; 493 } else if (type == TypedValue.TYPE_DIMENSION) { 494 return TypedValue.complexToDimensionPixelSize( 495 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 496 } 497 498 throw new RuntimeException(getPositionDescription() 499 + ": You must supply a " + name + " attribute."); 500 } 501 502 /** 503 * Special version of {@link #getDimensionPixelSize} for retrieving 504 * {@link android.view.ViewGroup}'s layout_width and layout_height 505 * attributes. This is only here for performance reasons; applications 506 * should use {@link #getDimensionPixelSize}. 507 * 508 * @param index Index of the attribute to retrieve. 509 * @param defValue The default value to return if this attribute is not 510 * default or contains the wrong type of data. 511 * 512 * @return Attribute dimension value multiplied by the appropriate 513 * metric and truncated to integer pixels. 514 */ 515 public int getLayoutDimension(int index, int defValue) { 516 index *= AssetManager.STYLE_NUM_ENTRIES; 517 final int[] data = mData; 518 final int type = data[index+AssetManager.STYLE_TYPE]; 519 if (type >= TypedValue.TYPE_FIRST_INT 520 && type <= TypedValue.TYPE_LAST_INT) { 521 return data[index+AssetManager.STYLE_DATA]; 522 } else if (type == TypedValue.TYPE_DIMENSION) { 523 return TypedValue.complexToDimensionPixelSize( 524 data[index+AssetManager.STYLE_DATA], mResources.mMetrics); 525 } 526 527 return defValue; 528 } 529 530 /** 531 * Retrieve a fractional unit attribute at <var>index</var>. 532 * 533 * @param index Index of attribute to retrieve. 534 * @param base The base value of this fraction. In other words, a 535 * standard fraction is multiplied by this value. 536 * @param pbase The parent base value of this fraction. In other 537 * words, a parent fraction (nn%p) is multiplied by this 538 * value. 539 * @param defValue Value to return if the attribute is not defined or 540 * not a resource. 541 * 542 * @return Attribute fractional value multiplied by the appropriate 543 * base value, or defValue if not defined. 544 */ 545 public float getFraction(int index, int base, int pbase, float defValue) { 546 index *= AssetManager.STYLE_NUM_ENTRIES; 547 final int[] data = mData; 548 final int type = data[index+AssetManager.STYLE_TYPE]; 549 if (type == TypedValue.TYPE_NULL) { 550 return defValue; 551 } else if (type == TypedValue.TYPE_FRACTION) { 552 return TypedValue.complexToFraction( 553 data[index+AssetManager.STYLE_DATA], base, pbase); 554 } 555 556 throw new UnsupportedOperationException("Can't convert to fraction: type=0x" 557 + Integer.toHexString(type)); 558 } 559 560 /** 561 * Retrieve the resource identifier for the attribute at 562 * <var>index</var>. Note that attribute resource as resolved when 563 * the overall {@link TypedArray} object is retrieved. As a 564 * result, this function will return the resource identifier of the 565 * final resource value that was found, <em>not</em> necessarily the 566 * original resource that was specified by the attribute. 567 * 568 * @param index Index of attribute to retrieve. 569 * @param defValue Value to return if the attribute is not defined or 570 * not a resource. 571 * 572 * @return Attribute resource identifier, or defValue if not defined. 573 */ 574 public int getResourceId(int index, int defValue) { 575 index *= AssetManager.STYLE_NUM_ENTRIES; 576 final int[] data = mData; 577 if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) { 578 final int resid = data[index+AssetManager.STYLE_RESOURCE_ID]; 579 if (resid != 0) { 580 return resid; 581 } 582 } 583 return defValue; 584 } 585 586 /** 587 * Retrieve the Drawable for the attribute at <var>index</var>. This 588 * gets the resource ID of the selected attribute, and uses 589 * {@link Resources#getDrawable Resources.getDrawable} of the owning 590 * Resources object to retrieve its Drawable. 591 * 592 * @param index Index of attribute to retrieve. 593 * 594 * @return Drawable for the attribute, or null if not defined. 595 */ 596 public Drawable getDrawable(int index) { 597 final TypedValue value = mValue; 598 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 599 if (false) { 600 System.out.println("******************************************************************"); 601 System.out.println("Got drawable resource: type=" 602 + value.type 603 + " str=" + value.string 604 + " int=0x" + Integer.toHexString(value.data) 605 + " cookie=" + value.assetCookie); 606 System.out.println("******************************************************************"); 607 } 608 return mResources.loadDrawable(value, value.resourceId); 609 } 610 return null; 611 } 612 613 /** 614 * Retrieve the CharSequence[] for the attribute at <var>index</var>. 615 * This gets the resource ID of the selected attribute, and uses 616 * {@link Resources#getTextArray Resources.getTextArray} of the owning 617 * Resources object to retrieve its String[]. 618 * 619 * @param index Index of attribute to retrieve. 620 * 621 * @return CharSequence[] for the attribute, or null if not defined. 622 */ 623 public CharSequence[] getTextArray(int index) { 624 final TypedValue value = mValue; 625 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 626 if (false) { 627 System.out.println("******************************************************************"); 628 System.out.println("Got drawable resource: type=" 629 + value.type 630 + " str=" + value.string 631 + " int=0x" + Integer.toHexString(value.data) 632 + " cookie=" + value.assetCookie); 633 System.out.println("******************************************************************"); 634 } 635 return mResources.getTextArray(value.resourceId); 636 } 637 return null; 638 } 639 640 /** 641 * Retrieve the raw TypedValue for the attribute at <var>index</var>. 642 * 643 * @param index Index of attribute to retrieve. 644 * @param outValue TypedValue object in which to place the attribute's 645 * data. 646 * 647 * @return Returns true if the value was retrieved, else false. 648 */ 649 public boolean getValue(int index, TypedValue outValue) { 650 return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue); 651 } 652 653 /** 654 * Determines whether there is an attribute at <var>index</var>. 655 * 656 * @param index Index of attribute to retrieve. 657 * 658 * @return True if the attribute has a value, false otherwise. 659 */ 660 public boolean hasValue(int index) { 661 index *= AssetManager.STYLE_NUM_ENTRIES; 662 final int[] data = mData; 663 final int type = data[index+AssetManager.STYLE_TYPE]; 664 return type != TypedValue.TYPE_NULL; 665 } 666 667 /** 668 * Retrieve the raw TypedValue for the attribute at <var>index</var> 669 * and return a temporary object holding its data. This object is only 670 * valid until the next call on to {@link TypedArray}. 671 * 672 * @param index Index of attribute to retrieve. 673 * 674 * @return Returns a TypedValue object if the attribute is defined, 675 * containing its data; otherwise returns null. (You will not 676 * receive a TypedValue whose type is TYPE_NULL.) 677 */ 678 public TypedValue peekValue(int index) { 679 final TypedValue value = mValue; 680 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 681 return value; 682 } 683 return null; 684 } 685 686 /** 687 * Returns a message about the parser state suitable for printing error messages. 688 */ 689 public String getPositionDescription() { 690 return mXml != null ? mXml.getPositionDescription() : "<internal>"; 691 } 692 693 /** 694 * Give back a previously retrieved array, for later re-use. 695 */ 696 public void recycle() { 697 synchronized (mResources.mTmpValue) { 698 TypedArray cached = mResources.mCachedStyledAttributes; 699 if (cached == null || cached.mData.length < mData.length) { 700 mXml = null; 701 mResources.mCachedStyledAttributes = this; 702 } 703 } 704 } 705 706 private boolean getValueAt(int index, TypedValue outValue) { 707 final int[] data = mData; 708 final int type = data[index+AssetManager.STYLE_TYPE]; 709 if (type == TypedValue.TYPE_NULL) { 710 return false; 711 } 712 outValue.type = type; 713 outValue.data = data[index+AssetManager.STYLE_DATA]; 714 outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 715 outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID]; 716 outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]; 717 outValue.density = data[index+AssetManager.STYLE_DENSITY]; 718 outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null; 719 return true; 720 } 721 722 private CharSequence loadStringValueAt(int index) { 723 final int[] data = mData; 724 final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 725 if (cookie < 0) { 726 if (mXml != null) { 727 return mXml.getPooledString( 728 data[index+AssetManager.STYLE_DATA]); 729 } 730 return null; 731 } 732 //System.out.println("Getting pooled from: " + v); 733 return mResources.mAssets.getPooledString( 734 cookie, data[index+AssetManager.STYLE_DATA]); 735 } 736 737 /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) { 738 mResources = resources; 739 mData = data; 740 mIndices = indices; 741 mLength = len; 742 } 743 744 public String toString() { 745 return Arrays.toString(mData); 746 } 747} 748