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