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