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