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.annotation.AnyRes; 20 import android.annotation.ColorInt; 21 import android.annotation.Nullable; 22 import android.annotation.StyleableRes; 23 import android.content.pm.ActivityInfo; 24 import android.content.pm.ActivityInfo.Config; 25 import android.graphics.Typeface; 26 import android.graphics.drawable.Drawable; 27 import android.os.StrictMode; 28 import android.util.AttributeSet; 29 import android.util.DisplayMetrics; 30 import android.util.TypedValue; 31 32 import com.android.internal.util.XmlUtils; 33 34 import dalvik.system.VMRuntime; 35 36 import java.util.Arrays; 37 38 /** 39 * Container for an array of values that were retrieved with 40 * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)} 41 * or {@link Resources#obtainAttributes}. Be 42 * sure to call {@link #recycle} when done with them. 43 * 44 * The indices used to retrieve values from this structure correspond to 45 * the positions of the attributes given to obtainStyledAttributes. 46 */ 47 public class TypedArray { 48 obtain(Resources res, int len)49 static TypedArray obtain(Resources res, int len) { 50 TypedArray attrs = res.mTypedArrayPool.acquire(); 51 if (attrs == null) { 52 attrs = new TypedArray(res); 53 } 54 55 attrs.mRecycled = false; 56 // Reset the assets, which may have changed due to configuration changes 57 // or further resource loading. 58 attrs.mAssets = res.getAssets(); 59 attrs.mMetrics = res.getDisplayMetrics(); 60 attrs.resize(len); 61 return attrs; 62 } 63 64 private final Resources mResources; 65 private DisplayMetrics mMetrics; 66 private AssetManager mAssets; 67 68 private boolean mRecycled; 69 70 /*package*/ XmlBlock.Parser mXml; 71 /*package*/ Resources.Theme mTheme; 72 /*package*/ int[] mData; 73 /*package*/ long mDataAddress; 74 /*package*/ int[] mIndices; 75 /*package*/ long mIndicesAddress; 76 /*package*/ int mLength; 77 /*package*/ TypedValue mValue = new TypedValue(); 78 resize(int len)79 private void resize(int len) { 80 mLength = len; 81 final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES; 82 final int indicesLen = len + 1; 83 final VMRuntime runtime = VMRuntime.getRuntime(); 84 if (mDataAddress == 0 || mData.length < dataLen) { 85 mData = (int[]) runtime.newNonMovableArray(int.class, dataLen); 86 mDataAddress = runtime.addressOf(mData); 87 mIndices = (int[]) runtime.newNonMovableArray(int.class, indicesLen); 88 mIndicesAddress = runtime.addressOf(mIndices); 89 } 90 } 91 92 /** 93 * Returns the number of values in this array. 94 * 95 * @throws RuntimeException if the TypedArray has already been recycled. 96 */ length()97 public int length() { 98 if (mRecycled) { 99 throw new RuntimeException("Cannot make calls to a recycled instance!"); 100 } 101 102 return mLength; 103 } 104 105 /** 106 * Returns the number of indices in the array that actually have data. Attributes with a value 107 * of @empty are included, as this is an explicit indicator. 108 * 109 * @throws RuntimeException if the TypedArray has already been recycled. 110 */ getIndexCount()111 public int getIndexCount() { 112 if (mRecycled) { 113 throw new RuntimeException("Cannot make calls to a recycled instance!"); 114 } 115 116 return mIndices[0]; 117 } 118 119 /** 120 * Returns an index in the array that has data. Attributes with a value of @empty are included, 121 * as this is an explicit indicator. 122 * 123 * @param at The index you would like to returned, ranging from 0 to 124 * {@link #getIndexCount()}. 125 * 126 * @return The index at the given offset, which can be used with 127 * {@link #getValue} and related APIs. 128 * @throws RuntimeException if the TypedArray has already been recycled. 129 */ getIndex(int at)130 public int getIndex(int at) { 131 if (mRecycled) { 132 throw new RuntimeException("Cannot make calls to a recycled instance!"); 133 } 134 135 return mIndices[1+at]; 136 } 137 138 /** 139 * Returns the Resources object this array was loaded from. 140 * 141 * @throws RuntimeException if the TypedArray has already been recycled. 142 */ getResources()143 public Resources getResources() { 144 if (mRecycled) { 145 throw new RuntimeException("Cannot make calls to a recycled instance!"); 146 } 147 148 return mResources; 149 } 150 151 /** 152 * Retrieves the styled string value for the attribute at <var>index</var>. 153 * <p> 154 * If the attribute is not a string, this method will attempt to coerce 155 * it to a string. 156 * 157 * @param index Index of attribute to retrieve. 158 * 159 * @return CharSequence holding string data. May be styled. Returns 160 * {@code null} if the attribute is not defined or could not be 161 * coerced to a string. 162 * @throws RuntimeException if the TypedArray has already been recycled. 163 */ getText(@tyleableRes int index)164 public CharSequence getText(@StyleableRes int index) { 165 if (mRecycled) { 166 throw new RuntimeException("Cannot make calls to a recycled instance!"); 167 } 168 169 index *= AssetManager.STYLE_NUM_ENTRIES; 170 final int[] data = mData; 171 final int type = data[index+AssetManager.STYLE_TYPE]; 172 if (type == TypedValue.TYPE_NULL) { 173 return null; 174 } else if (type == TypedValue.TYPE_STRING) { 175 return loadStringValueAt(index); 176 } 177 178 final TypedValue v = mValue; 179 if (getValueAt(index, v)) { 180 return v.coerceToString(); 181 } 182 183 // We already checked for TYPE_NULL. This should never happen. 184 throw new RuntimeException("getText of bad type: 0x" + Integer.toHexString(type)); 185 } 186 187 /** 188 * Retrieves the string value for the attribute at <var>index</var>. 189 * <p> 190 * If the attribute is not a string, this method will attempt to coerce 191 * it to a string. 192 * 193 * @param index Index of attribute to retrieve. 194 * 195 * @return String holding string data. Any styling information is removed. 196 * Returns {@code null} if the attribute is not defined or could 197 * not be coerced to a string. 198 * @throws RuntimeException if the TypedArray has already been recycled. 199 */ 200 @Nullable getString(@tyleableRes int index)201 public String getString(@StyleableRes int index) { 202 if (mRecycled) { 203 throw new RuntimeException("Cannot make calls to a recycled instance!"); 204 } 205 206 index *= AssetManager.STYLE_NUM_ENTRIES; 207 final int[] data = mData; 208 final int type = data[index+AssetManager.STYLE_TYPE]; 209 if (type == TypedValue.TYPE_NULL) { 210 return null; 211 } else if (type == TypedValue.TYPE_STRING) { 212 return loadStringValueAt(index).toString(); 213 } 214 215 final TypedValue v = mValue; 216 if (getValueAt(index, v)) { 217 final CharSequence cs = v.coerceToString(); 218 return cs != null ? cs.toString() : null; 219 } 220 221 // We already checked for TYPE_NULL. This should never happen. 222 throw new RuntimeException("getString of bad type: 0x" + Integer.toHexString(type)); 223 } 224 225 /** 226 * Retrieves the string value for the attribute at <var>index</var>, but 227 * only if that string comes from an immediate value in an XML file. That 228 * is, this does not allow references to string resources, string 229 * attributes, or conversions from other types. As such, this method 230 * will only return strings for TypedArray objects that come from 231 * attributes in an XML file. 232 * 233 * @param index Index of attribute to retrieve. 234 * 235 * @return String holding string data. Any styling information is removed. 236 * Returns {@code null} if the attribute is not defined or is not 237 * an immediate string value. 238 * @throws RuntimeException if the TypedArray has already been recycled. 239 */ getNonResourceString(@tyleableRes int index)240 public String getNonResourceString(@StyleableRes int index) { 241 if (mRecycled) { 242 throw new RuntimeException("Cannot make calls to a recycled instance!"); 243 } 244 245 index *= AssetManager.STYLE_NUM_ENTRIES; 246 final int[] data = mData; 247 final int type = data[index+AssetManager.STYLE_TYPE]; 248 if (type == TypedValue.TYPE_STRING) { 249 final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 250 if (cookie < 0) { 251 return mXml.getPooledString( 252 data[index+AssetManager.STYLE_DATA]).toString(); 253 } 254 } 255 return null; 256 } 257 258 /** 259 * Retrieves the string value for the attribute at <var>index</var> that is 260 * not allowed to change with the given configurations. 261 * 262 * @param index Index of attribute to retrieve. 263 * @param allowedChangingConfigs Bit mask of configurations from 264 * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change. 265 * 266 * @return String holding string data. Any styling information is removed. 267 * Returns {@code null} if the attribute is not defined. 268 * @throws RuntimeException if the TypedArray has already been recycled. 269 * @hide 270 */ getNonConfigurationString(@tyleableRes int index, @Config int allowedChangingConfigs)271 public String getNonConfigurationString(@StyleableRes int index, 272 @Config int allowedChangingConfigs) { 273 if (mRecycled) { 274 throw new RuntimeException("Cannot make calls to a recycled instance!"); 275 } 276 277 index *= AssetManager.STYLE_NUM_ENTRIES; 278 final int[] data = mData; 279 final int type = data[index+AssetManager.STYLE_TYPE]; 280 final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava( 281 data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]); 282 if ((changingConfigs & ~allowedChangingConfigs) != 0) { 283 return null; 284 } 285 if (type == TypedValue.TYPE_NULL) { 286 return null; 287 } else if (type == TypedValue.TYPE_STRING) { 288 return loadStringValueAt(index).toString(); 289 } 290 291 final TypedValue v = mValue; 292 if (getValueAt(index, v)) { 293 final CharSequence cs = v.coerceToString(); 294 return cs != null ? cs.toString() : null; 295 } 296 297 // We already checked for TYPE_NULL. This should never happen. 298 throw new RuntimeException("getNonConfigurationString of bad type: 0x" 299 + Integer.toHexString(type)); 300 } 301 302 /** 303 * Retrieve the boolean value for the attribute at <var>index</var>. 304 * <p> 305 * If the attribute is an integer value, this method will return whether 306 * it is equal to zero. If the attribute is not a boolean or integer value, 307 * this method will attempt to coerce it to an integer using 308 * {@link Integer#decode(String)} and return whether it is equal to zero. 309 * 310 * @param index Index of attribute to retrieve. 311 * @param defValue Value to return if the attribute is not defined or 312 * cannot be coerced to an integer. 313 * 314 * @return Boolean value of the attribute, or defValue if the attribute was 315 * not defined or could not be coerced to an integer. 316 * @throws RuntimeException if the TypedArray has already been recycled. 317 */ getBoolean(@tyleableRes int index, boolean defValue)318 public boolean getBoolean(@StyleableRes int index, boolean defValue) { 319 if (mRecycled) { 320 throw new RuntimeException("Cannot make calls to a recycled instance!"); 321 } 322 323 index *= AssetManager.STYLE_NUM_ENTRIES; 324 final int[] data = mData; 325 final int type = data[index+AssetManager.STYLE_TYPE]; 326 if (type == TypedValue.TYPE_NULL) { 327 return defValue; 328 } else if (type >= TypedValue.TYPE_FIRST_INT 329 && type <= TypedValue.TYPE_LAST_INT) { 330 return data[index+AssetManager.STYLE_DATA] != 0; 331 } 332 333 final TypedValue v = mValue; 334 if (getValueAt(index, v)) { 335 StrictMode.noteResourceMismatch(v); 336 return XmlUtils.convertValueToBoolean(v.coerceToString(), defValue); 337 } 338 339 // We already checked for TYPE_NULL. This should never happen. 340 throw new RuntimeException("getBoolean of bad type: 0x" + Integer.toHexString(type)); 341 } 342 343 /** 344 * Retrieve the integer value for the attribute at <var>index</var>. 345 * <p> 346 * If the attribute is not an integer, this method will attempt to coerce 347 * it to an integer using {@link Integer#decode(String)}. 348 * 349 * @param index Index of attribute to retrieve. 350 * @param defValue Value to return if the attribute is not defined or 351 * cannot be coerced to an integer. 352 * 353 * @return Integer value of the attribute, or defValue if the attribute was 354 * not defined or could not be coerced to an integer. 355 * @throws RuntimeException if the TypedArray has already been recycled. 356 */ getInt(@tyleableRes int index, int defValue)357 public int getInt(@StyleableRes int index, int defValue) { 358 if (mRecycled) { 359 throw new RuntimeException("Cannot make calls to a recycled instance!"); 360 } 361 362 index *= AssetManager.STYLE_NUM_ENTRIES; 363 final int[] data = mData; 364 final int type = data[index+AssetManager.STYLE_TYPE]; 365 if (type == TypedValue.TYPE_NULL) { 366 return defValue; 367 } else if (type >= TypedValue.TYPE_FIRST_INT 368 && type <= TypedValue.TYPE_LAST_INT) { 369 return data[index+AssetManager.STYLE_DATA]; 370 } 371 372 final TypedValue v = mValue; 373 if (getValueAt(index, v)) { 374 StrictMode.noteResourceMismatch(v); 375 return XmlUtils.convertValueToInt(v.coerceToString(), defValue); 376 } 377 378 // We already checked for TYPE_NULL. This should never happen. 379 throw new RuntimeException("getInt of bad type: 0x" + Integer.toHexString(type)); 380 } 381 382 /** 383 * Retrieve the float value for the attribute at <var>index</var>. 384 * <p> 385 * If the attribute is not a float or an integer, this method will attempt 386 * to coerce it to a float using {@link Float#parseFloat(String)}. 387 * 388 * @param index Index of attribute to retrieve. 389 * 390 * @return Attribute float value, or defValue if the attribute was 391 * not defined or could not be coerced to a float. 392 * @throws RuntimeException if the TypedArray has already been recycled. 393 */ getFloat(@tyleableRes int index, float defValue)394 public float getFloat(@StyleableRes int index, float defValue) { 395 if (mRecycled) { 396 throw new RuntimeException("Cannot make calls to a recycled instance!"); 397 } 398 399 index *= AssetManager.STYLE_NUM_ENTRIES; 400 final int[] data = mData; 401 final int type = data[index+AssetManager.STYLE_TYPE]; 402 if (type == TypedValue.TYPE_NULL) { 403 return defValue; 404 } else if (type == TypedValue.TYPE_FLOAT) { 405 return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]); 406 } else if (type >= TypedValue.TYPE_FIRST_INT 407 && type <= TypedValue.TYPE_LAST_INT) { 408 return data[index+AssetManager.STYLE_DATA]; 409 } 410 411 final TypedValue v = mValue; 412 if (getValueAt(index, v)) { 413 final CharSequence str = v.coerceToString(); 414 if (str != null) { 415 StrictMode.noteResourceMismatch(v); 416 return Float.parseFloat(str.toString()); 417 } 418 } 419 420 // We already checked for TYPE_NULL. This should never happen. 421 throw new RuntimeException("getFloat of bad type: 0x" + Integer.toHexString(type)); 422 } 423 424 /** 425 * Retrieve the color value for the attribute at <var>index</var>. If 426 * the attribute references a color resource holding a complex 427 * {@link android.content.res.ColorStateList}, then the default color from 428 * the set is returned. 429 * <p> 430 * This method will throw an exception if the attribute is defined but is 431 * not an integer color or color state list. 432 * 433 * @param index Index of attribute to retrieve. 434 * @param defValue Value to return if the attribute is not defined or 435 * not a resource. 436 * 437 * @return Attribute color value, or defValue if not defined. 438 * @throws RuntimeException if the TypedArray has already been recycled. 439 * @throws UnsupportedOperationException if the attribute is defined but is 440 * not an integer color or color state list. 441 */ 442 @ColorInt getColor(@tyleableRes int index, @ColorInt int defValue)443 public int getColor(@StyleableRes int index, @ColorInt int defValue) { 444 if (mRecycled) { 445 throw new RuntimeException("Cannot make calls to a recycled instance!"); 446 } 447 448 final int attrIndex = index; 449 index *= AssetManager.STYLE_NUM_ENTRIES; 450 451 final int[] data = mData; 452 final int type = data[index+AssetManager.STYLE_TYPE]; 453 if (type == TypedValue.TYPE_NULL) { 454 return defValue; 455 } else if (type >= TypedValue.TYPE_FIRST_INT 456 && type <= TypedValue.TYPE_LAST_INT) { 457 return data[index+AssetManager.STYLE_DATA]; 458 } else if (type == TypedValue.TYPE_STRING) { 459 final TypedValue value = mValue; 460 if (getValueAt(index, value)) { 461 final ColorStateList csl = mResources.loadColorStateList( 462 value, value.resourceId, mTheme); 463 return csl.getDefaultColor(); 464 } 465 return defValue; 466 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 467 final TypedValue value = mValue; 468 getValueAt(index, value); 469 throw new UnsupportedOperationException( 470 "Failed to resolve attribute at index " + attrIndex + ": " + value); 471 } 472 473 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 474 + " to color: type=0x" + Integer.toHexString(type)); 475 } 476 477 /** 478 * Retrieve the ComplexColor for the attribute at <var>index</var>. 479 * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple 480 * color value or a {@link android.content.res.GradientColor} 481 * <p> 482 * This method will return {@code null} if the attribute is not defined or 483 * is not an integer color, color state list or GradientColor. 484 * 485 * @param index Index of attribute to retrieve. 486 * 487 * @return ComplexColor for the attribute, or {@code null} if not defined. 488 * @throws RuntimeException if the attribute if the TypedArray has already 489 * been recycled. 490 * @throws UnsupportedOperationException if the attribute is defined but is 491 * not an integer color, color state list or GradientColor. 492 * @hide 493 */ 494 @Nullable getComplexColor(@tyleableRes int index)495 public ComplexColor getComplexColor(@StyleableRes int index) { 496 if (mRecycled) { 497 throw new RuntimeException("Cannot make calls to a recycled instance!"); 498 } 499 500 final TypedValue value = mValue; 501 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 502 if (value.type == TypedValue.TYPE_ATTRIBUTE) { 503 throw new UnsupportedOperationException( 504 "Failed to resolve attribute at index " + index + ": " + value); 505 } 506 return mResources.loadComplexColor(value, value.resourceId, mTheme); 507 } 508 return null; 509 } 510 511 /** 512 * Retrieve the ColorStateList for the attribute at <var>index</var>. 513 * The value may be either a single solid color or a reference to 514 * a color or complex {@link android.content.res.ColorStateList} 515 * description. 516 * <p> 517 * This method will return {@code null} if the attribute is not defined or 518 * is not an integer color or color state list. 519 * 520 * @param index Index of attribute to retrieve. 521 * 522 * @return ColorStateList for the attribute, or {@code null} if not 523 * defined. 524 * @throws RuntimeException if the attribute if the TypedArray has already 525 * been recycled. 526 * @throws UnsupportedOperationException if the attribute is defined but is 527 * not an integer color or color state list. 528 */ 529 @Nullable getColorStateList(@tyleableRes int index)530 public ColorStateList getColorStateList(@StyleableRes int index) { 531 if (mRecycled) { 532 throw new RuntimeException("Cannot make calls to a recycled instance!"); 533 } 534 535 final TypedValue value = mValue; 536 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 537 if (value.type == TypedValue.TYPE_ATTRIBUTE) { 538 throw new UnsupportedOperationException( 539 "Failed to resolve attribute at index " + index + ": " + value); 540 } 541 return mResources.loadColorStateList(value, value.resourceId, mTheme); 542 } 543 return null; 544 } 545 546 /** 547 * Retrieve the integer value for the attribute at <var>index</var>. 548 * <p> 549 * Unlike {@link #getInt(int, int)}, this method will throw an exception if 550 * the attribute is defined but is not an integer. 551 * 552 * @param index Index of attribute to retrieve. 553 * @param defValue Value to return if the attribute is not defined or 554 * not a resource. 555 * 556 * @return Attribute integer value, or defValue if not defined. 557 * @throws RuntimeException if the TypedArray has already been recycled. 558 * @throws UnsupportedOperationException if the attribute is defined but is 559 * not an integer. 560 */ getInteger(@tyleableRes int index, int defValue)561 public int getInteger(@StyleableRes int index, int defValue) { 562 if (mRecycled) { 563 throw new RuntimeException("Cannot make calls to a recycled instance!"); 564 } 565 566 final int attrIndex = index; 567 index *= AssetManager.STYLE_NUM_ENTRIES; 568 569 final int[] data = mData; 570 final int type = data[index+AssetManager.STYLE_TYPE]; 571 if (type == TypedValue.TYPE_NULL) { 572 return defValue; 573 } else if (type >= TypedValue.TYPE_FIRST_INT 574 && type <= TypedValue.TYPE_LAST_INT) { 575 return data[index+AssetManager.STYLE_DATA]; 576 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 577 final TypedValue value = mValue; 578 getValueAt(index, value); 579 throw new UnsupportedOperationException( 580 "Failed to resolve attribute at index " + attrIndex + ": " + value); 581 } 582 583 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 584 + " to integer: type=0x" + Integer.toHexString(type)); 585 } 586 587 /** 588 * Retrieve a dimensional unit attribute at <var>index</var>. Unit 589 * conversions are based on the current {@link DisplayMetrics} 590 * associated with the resources this {@link TypedArray} object 591 * came from. 592 * <p> 593 * This method will throw an exception if the attribute is defined but is 594 * not a dimension. 595 * 596 * @param index Index of attribute to retrieve. 597 * @param defValue Value to return if the attribute is not defined or 598 * not a resource. 599 * 600 * @return Attribute dimension value multiplied by the appropriate 601 * metric, or defValue if not defined. 602 * @throws RuntimeException if the TypedArray has already been recycled. 603 * @throws UnsupportedOperationException if the attribute is defined but is 604 * not an integer. 605 * 606 * @see #getDimensionPixelOffset 607 * @see #getDimensionPixelSize 608 */ getDimension(@tyleableRes int index, float defValue)609 public float getDimension(@StyleableRes int index, float defValue) { 610 if (mRecycled) { 611 throw new RuntimeException("Cannot make calls to a recycled instance!"); 612 } 613 614 final int attrIndex = index; 615 index *= AssetManager.STYLE_NUM_ENTRIES; 616 617 final int[] data = mData; 618 final int type = data[index+AssetManager.STYLE_TYPE]; 619 if (type == TypedValue.TYPE_NULL) { 620 return defValue; 621 } else if (type == TypedValue.TYPE_DIMENSION) { 622 return TypedValue.complexToDimension( 623 data[index + AssetManager.STYLE_DATA], mMetrics); 624 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 625 final TypedValue value = mValue; 626 getValueAt(index, value); 627 throw new UnsupportedOperationException( 628 "Failed to resolve attribute at index " + attrIndex + ": " + value); 629 } 630 631 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 632 + " to dimension: type=0x" + Integer.toHexString(type)); 633 } 634 635 /** 636 * Retrieve a dimensional unit attribute at <var>index</var> for use 637 * as an offset in raw pixels. This is the same as 638 * {@link #getDimension}, except the returned value is converted to 639 * integer pixels for you. An offset conversion involves simply 640 * truncating the base value to an integer. 641 * <p> 642 * This method will throw an exception if the attribute is defined but is 643 * not a dimension. 644 * 645 * @param index Index of attribute to retrieve. 646 * @param defValue Value to return if the attribute is not defined or 647 * not a resource. 648 * 649 * @return Attribute dimension value multiplied by the appropriate 650 * metric and truncated to integer pixels, or defValue if not defined. 651 * @throws RuntimeException if the TypedArray has already been recycled. 652 * @throws UnsupportedOperationException if the attribute is defined but is 653 * not an integer. 654 * 655 * @see #getDimension 656 * @see #getDimensionPixelSize 657 */ getDimensionPixelOffset(@tyleableRes int index, int defValue)658 public int getDimensionPixelOffset(@StyleableRes int index, int defValue) { 659 if (mRecycled) { 660 throw new RuntimeException("Cannot make calls to a recycled instance!"); 661 } 662 663 final int attrIndex = index; 664 index *= AssetManager.STYLE_NUM_ENTRIES; 665 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_DIMENSION) { 671 return TypedValue.complexToDimensionPixelOffset( 672 data[index + AssetManager.STYLE_DATA], mMetrics); 673 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 674 final TypedValue value = mValue; 675 getValueAt(index, value); 676 throw new UnsupportedOperationException( 677 "Failed to resolve attribute at index " + attrIndex + ": " + value); 678 } 679 680 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 681 + " to dimension: type=0x" + Integer.toHexString(type)); 682 } 683 684 /** 685 * Retrieve a dimensional unit attribute at <var>index</var> for use 686 * as a size in raw pixels. This is the same as 687 * {@link #getDimension}, except the returned value is converted to 688 * integer pixels for use as a size. A size conversion involves 689 * rounding the base value, and ensuring that a non-zero base value 690 * is at least one pixel in size. 691 * <p> 692 * This method will throw an exception if the attribute is defined but is 693 * not a dimension. 694 * 695 * @param index Index of attribute to retrieve. 696 * @param defValue Value to return if the attribute is not defined or 697 * not a resource. 698 * 699 * @return Attribute dimension value multiplied by the appropriate 700 * metric and truncated to integer pixels, or defValue if not defined. 701 * @throws RuntimeException if the TypedArray has already been recycled. 702 * @throws UnsupportedOperationException if the attribute is defined but is 703 * not a dimension. 704 * 705 * @see #getDimension 706 * @see #getDimensionPixelOffset 707 */ getDimensionPixelSize(@tyleableRes int index, int defValue)708 public int getDimensionPixelSize(@StyleableRes int index, int defValue) { 709 if (mRecycled) { 710 throw new RuntimeException("Cannot make calls to a recycled instance!"); 711 } 712 713 final int attrIndex = index; 714 index *= AssetManager.STYLE_NUM_ENTRIES; 715 716 final int[] data = mData; 717 final int type = data[index+AssetManager.STYLE_TYPE]; 718 if (type == TypedValue.TYPE_NULL) { 719 return defValue; 720 } else if (type == TypedValue.TYPE_DIMENSION) { 721 return TypedValue.complexToDimensionPixelSize( 722 data[index+AssetManager.STYLE_DATA], mMetrics); 723 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 724 final TypedValue value = mValue; 725 getValueAt(index, value); 726 throw new UnsupportedOperationException( 727 "Failed to resolve attribute at index " + attrIndex + ": " + value); 728 } 729 730 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 731 + " to dimension: type=0x" + Integer.toHexString(type)); 732 } 733 734 /** 735 * Special version of {@link #getDimensionPixelSize} for retrieving 736 * {@link android.view.ViewGroup}'s layout_width and layout_height 737 * attributes. This is only here for performance reasons; applications 738 * should use {@link #getDimensionPixelSize}. 739 * <p> 740 * This method will throw an exception if the attribute is defined but is 741 * not a dimension or integer (enum). 742 * 743 * @param index Index of the attribute to retrieve. 744 * @param name Textual name of attribute for error reporting. 745 * 746 * @return Attribute dimension value multiplied by the appropriate 747 * metric and truncated to integer pixels. 748 * @throws RuntimeException if the TypedArray has already been recycled. 749 * @throws UnsupportedOperationException if the attribute is defined but is 750 * not a dimension or integer (enum). 751 */ getLayoutDimension(@tyleableRes int index, String name)752 public int getLayoutDimension(@StyleableRes int index, String name) { 753 if (mRecycled) { 754 throw new RuntimeException("Cannot make calls to a recycled instance!"); 755 } 756 757 final int attrIndex = index; 758 index *= AssetManager.STYLE_NUM_ENTRIES; 759 760 final int[] data = mData; 761 final int type = data[index+AssetManager.STYLE_TYPE]; 762 if (type >= TypedValue.TYPE_FIRST_INT 763 && type <= TypedValue.TYPE_LAST_INT) { 764 return data[index+AssetManager.STYLE_DATA]; 765 } else if (type == TypedValue.TYPE_DIMENSION) { 766 return TypedValue.complexToDimensionPixelSize( 767 data[index+AssetManager.STYLE_DATA], mMetrics); 768 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 769 final TypedValue value = mValue; 770 getValueAt(index, value); 771 throw new UnsupportedOperationException( 772 "Failed to resolve attribute at index " + attrIndex + ": " + value); 773 } 774 775 throw new UnsupportedOperationException(getPositionDescription() 776 + ": You must supply a " + name + " attribute."); 777 } 778 779 /** 780 * Special version of {@link #getDimensionPixelSize} for retrieving 781 * {@link android.view.ViewGroup}'s layout_width and layout_height 782 * attributes. This is only here for performance reasons; applications 783 * should use {@link #getDimensionPixelSize}. 784 * 785 * @param index Index of the attribute to retrieve. 786 * @param defValue The default value to return if this attribute is not 787 * default or contains the wrong type of data. 788 * 789 * @return Attribute dimension value multiplied by the appropriate 790 * metric and truncated to integer pixels. 791 * @throws RuntimeException if the TypedArray has already been recycled. 792 */ getLayoutDimension(@tyleableRes int index, int defValue)793 public int getLayoutDimension(@StyleableRes int index, int defValue) { 794 if (mRecycled) { 795 throw new RuntimeException("Cannot make calls to a recycled instance!"); 796 } 797 798 index *= AssetManager.STYLE_NUM_ENTRIES; 799 final int[] data = mData; 800 final int type = data[index+AssetManager.STYLE_TYPE]; 801 if (type >= TypedValue.TYPE_FIRST_INT 802 && type <= TypedValue.TYPE_LAST_INT) { 803 return data[index+AssetManager.STYLE_DATA]; 804 } else if (type == TypedValue.TYPE_DIMENSION) { 805 return TypedValue.complexToDimensionPixelSize( 806 data[index + AssetManager.STYLE_DATA], mMetrics); 807 } 808 809 return defValue; 810 } 811 812 /** 813 * Retrieves a fractional unit attribute at <var>index</var>. 814 * 815 * @param index Index of attribute to retrieve. 816 * @param base The base value of this fraction. In other words, a 817 * standard fraction is multiplied by this value. 818 * @param pbase The parent base value of this fraction. In other 819 * words, a parent fraction (nn%p) is multiplied by this 820 * value. 821 * @param defValue Value to return if the attribute is not defined or 822 * not a resource. 823 * 824 * @return Attribute fractional value multiplied by the appropriate 825 * base value, or defValue if not defined. 826 * @throws RuntimeException if the TypedArray has already been recycled. 827 * @throws UnsupportedOperationException if the attribute is defined but is 828 * not a fraction. 829 */ getFraction(@tyleableRes int index, int base, int pbase, float defValue)830 public float getFraction(@StyleableRes int index, int base, int pbase, float defValue) { 831 if (mRecycled) { 832 throw new RuntimeException("Cannot make calls to a recycled instance!"); 833 } 834 835 final int attrIndex = index; 836 index *= AssetManager.STYLE_NUM_ENTRIES; 837 838 final int[] data = mData; 839 final int type = data[index+AssetManager.STYLE_TYPE]; 840 if (type == TypedValue.TYPE_NULL) { 841 return defValue; 842 } else if (type == TypedValue.TYPE_FRACTION) { 843 return TypedValue.complexToFraction( 844 data[index+AssetManager.STYLE_DATA], base, pbase); 845 } else if (type == TypedValue.TYPE_ATTRIBUTE) { 846 final TypedValue value = mValue; 847 getValueAt(index, value); 848 throw new UnsupportedOperationException( 849 "Failed to resolve attribute at index " + attrIndex + ": " + value); 850 } 851 852 throw new UnsupportedOperationException("Can't convert value at index " + attrIndex 853 + " to fraction: type=0x" + Integer.toHexString(type)); 854 } 855 856 /** 857 * Retrieves the resource identifier for the attribute at 858 * <var>index</var>. Note that attribute resource as resolved when 859 * the overall {@link TypedArray} object is retrieved. As a 860 * result, this function will return the resource identifier of the 861 * final resource value that was found, <em>not</em> necessarily the 862 * original resource that was specified by the attribute. 863 * 864 * @param index Index of attribute to retrieve. 865 * @param defValue Value to return if the attribute is not defined or 866 * not a resource. 867 * 868 * @return Attribute resource identifier, or defValue if not defined. 869 * @throws RuntimeException if the TypedArray has already been recycled. 870 */ 871 @AnyRes getResourceId(@tyleableRes int index, int defValue)872 public int getResourceId(@StyleableRes int index, int defValue) { 873 if (mRecycled) { 874 throw new RuntimeException("Cannot make calls to a recycled instance!"); 875 } 876 877 index *= AssetManager.STYLE_NUM_ENTRIES; 878 final int[] data = mData; 879 if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) { 880 final int resid = data[index+AssetManager.STYLE_RESOURCE_ID]; 881 if (resid != 0) { 882 return resid; 883 } 884 } 885 return defValue; 886 } 887 888 /** 889 * Retrieves the theme attribute resource identifier for the attribute at 890 * <var>index</var>. 891 * 892 * @param index Index of attribute to retrieve. 893 * @param defValue Value to return if the attribute is not defined or not a 894 * resource. 895 * 896 * @return Theme attribute resource identifier, or defValue if not defined. 897 * @throws RuntimeException if the TypedArray has already been recycled. 898 * @hide 899 */ getThemeAttributeId(@tyleableRes int index, int defValue)900 public int getThemeAttributeId(@StyleableRes int index, int defValue) { 901 if (mRecycled) { 902 throw new RuntimeException("Cannot make calls to a recycled instance!"); 903 } 904 905 index *= AssetManager.STYLE_NUM_ENTRIES; 906 final int[] data = mData; 907 if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) { 908 return data[index + AssetManager.STYLE_DATA]; 909 } 910 return defValue; 911 } 912 913 /** 914 * Retrieve the Drawable for the attribute at <var>index</var>. 915 * <p> 916 * This method will throw an exception if the attribute is defined but is 917 * not a color or drawable resource. 918 * 919 * @param index Index of attribute to retrieve. 920 * 921 * @return Drawable for the attribute, or {@code null} if not defined. 922 * @throws RuntimeException if the TypedArray has already been recycled. 923 * @throws UnsupportedOperationException if the attribute is defined but is 924 * not a color or drawable resource. 925 */ 926 @Nullable getDrawable(@tyleableRes int index)927 public Drawable getDrawable(@StyleableRes int index) { 928 return getDrawableForDensity(index, 0); 929 } 930 931 /** 932 * Version of {@link #getDrawable(int)} that accepts an override density. 933 * @hide 934 */ 935 @Nullable getDrawableForDensity(@tyleableRes int index, int density)936 public Drawable getDrawableForDensity(@StyleableRes int index, int density) { 937 if (mRecycled) { 938 throw new RuntimeException("Cannot make calls to a recycled instance!"); 939 } 940 941 final TypedValue value = mValue; 942 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 943 if (value.type == TypedValue.TYPE_ATTRIBUTE) { 944 throw new UnsupportedOperationException( 945 "Failed to resolve attribute at index " + index + ": " + value); 946 } 947 948 if (density > 0) { 949 // If the density is overridden, the value in the TypedArray will not reflect this. 950 // Do a separate lookup of the resourceId with the density override. 951 mResources.getValueForDensity(value.resourceId, density, value, true); 952 } 953 return mResources.loadDrawable(value, value.resourceId, density, mTheme); 954 } 955 return null; 956 } 957 958 /** 959 * Retrieve the Typeface for the attribute at <var>index</var>. 960 * <p> 961 * This method will throw an exception if the attribute is defined but is 962 * not a font. 963 * 964 * @param index Index of attribute to retrieve. 965 * 966 * @return Typeface for the attribute, or {@code null} if not defined. 967 * @throws RuntimeException if the TypedArray has already been recycled. 968 * @throws UnsupportedOperationException if the attribute is defined but is 969 * not a font resource. 970 */ 971 @Nullable getFont(@tyleableRes int index)972 public Typeface getFont(@StyleableRes int index) { 973 if (mRecycled) { 974 throw new RuntimeException("Cannot make calls to a recycled instance!"); 975 } 976 977 final TypedValue value = mValue; 978 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 979 if (value.type == TypedValue.TYPE_ATTRIBUTE) { 980 throw new UnsupportedOperationException( 981 "Failed to resolve attribute at index " + index + ": " + value); 982 } 983 return mResources.getFont(value, value.resourceId); 984 } 985 return null; 986 } 987 988 /** 989 * Retrieve the CharSequence[] for the attribute at <var>index</var>. 990 * This gets the resource ID of the selected attribute, and uses 991 * {@link Resources#getTextArray Resources.getTextArray} of the owning 992 * Resources object to retrieve its String[]. 993 * <p> 994 * This method will throw an exception if the attribute is defined but is 995 * not a text array resource. 996 * 997 * @param index Index of attribute to retrieve. 998 * 999 * @return CharSequence[] for the attribute, or {@code null} if not 1000 * defined. 1001 * @throws RuntimeException if the TypedArray has already been recycled. 1002 */ getTextArray(@tyleableRes int index)1003 public CharSequence[] getTextArray(@StyleableRes int index) { 1004 if (mRecycled) { 1005 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1006 } 1007 1008 final TypedValue value = mValue; 1009 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 1010 return mResources.getTextArray(value.resourceId); 1011 } 1012 return null; 1013 } 1014 1015 /** 1016 * Retrieve the raw TypedValue for the attribute at <var>index</var>. 1017 * 1018 * @param index Index of attribute to retrieve. 1019 * @param outValue TypedValue object in which to place the attribute's 1020 * data. 1021 * 1022 * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise. 1023 * @throws RuntimeException if the TypedArray has already been recycled. 1024 */ getValue(@tyleableRes int index, TypedValue outValue)1025 public boolean getValue(@StyleableRes int index, TypedValue outValue) { 1026 if (mRecycled) { 1027 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1028 } 1029 1030 return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue); 1031 } 1032 1033 /** 1034 * Returns the type of attribute at the specified index. 1035 * 1036 * @param index Index of attribute whose type to retrieve. 1037 * 1038 * @return Attribute type. 1039 * @throws RuntimeException if the TypedArray has already been recycled. 1040 */ getType(@tyleableRes int index)1041 public int getType(@StyleableRes int index) { 1042 if (mRecycled) { 1043 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1044 } 1045 1046 index *= AssetManager.STYLE_NUM_ENTRIES; 1047 return mData[index + AssetManager.STYLE_TYPE]; 1048 } 1049 1050 /** 1051 * Determines whether there is an attribute at <var>index</var>. 1052 * <p> 1053 * <strong>Note:</strong> If the attribute was set to {@code @empty} or 1054 * {@code @undefined}, this method returns {@code false}. 1055 * 1056 * @param index Index of attribute to retrieve. 1057 * 1058 * @return True if the attribute has a value, false otherwise. 1059 * @throws RuntimeException if the TypedArray has already been recycled. 1060 */ hasValue(@tyleableRes int index)1061 public boolean hasValue(@StyleableRes int index) { 1062 if (mRecycled) { 1063 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1064 } 1065 1066 index *= AssetManager.STYLE_NUM_ENTRIES; 1067 final int[] data = mData; 1068 final int type = data[index+AssetManager.STYLE_TYPE]; 1069 return type != TypedValue.TYPE_NULL; 1070 } 1071 1072 /** 1073 * Determines whether there is an attribute at <var>index</var>, returning 1074 * {@code true} if the attribute was explicitly set to {@code @empty} and 1075 * {@code false} only if the attribute was undefined. 1076 * 1077 * @param index Index of attribute to retrieve. 1078 * 1079 * @return True if the attribute has a value or is empty, false otherwise. 1080 * @throws RuntimeException if the TypedArray has already been recycled. 1081 */ hasValueOrEmpty(@tyleableRes int index)1082 public boolean hasValueOrEmpty(@StyleableRes int index) { 1083 if (mRecycled) { 1084 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1085 } 1086 1087 index *= AssetManager.STYLE_NUM_ENTRIES; 1088 final int[] data = mData; 1089 final int type = data[index+AssetManager.STYLE_TYPE]; 1090 return type != TypedValue.TYPE_NULL 1091 || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY; 1092 } 1093 1094 /** 1095 * Retrieve the raw TypedValue for the attribute at <var>index</var> 1096 * and return a temporary object holding its data. This object is only 1097 * valid until the next call on to {@link TypedArray}. 1098 * 1099 * @param index Index of attribute to retrieve. 1100 * 1101 * @return Returns a TypedValue object if the attribute is defined, 1102 * containing its data; otherwise returns null. (You will not 1103 * receive a TypedValue whose type is TYPE_NULL.) 1104 * @throws RuntimeException if the TypedArray has already been recycled. 1105 */ peekValue(@tyleableRes int index)1106 public TypedValue peekValue(@StyleableRes int index) { 1107 if (mRecycled) { 1108 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1109 } 1110 1111 final TypedValue value = mValue; 1112 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { 1113 return value; 1114 } 1115 return null; 1116 } 1117 1118 /** 1119 * Returns a message about the parser state suitable for printing error messages. 1120 * 1121 * @return Human-readable description of current parser state. 1122 * @throws RuntimeException if the TypedArray has already been recycled. 1123 */ getPositionDescription()1124 public String getPositionDescription() { 1125 if (mRecycled) { 1126 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1127 } 1128 1129 return mXml != null ? mXml.getPositionDescription() : "<internal>"; 1130 } 1131 1132 /** 1133 * Recycles the TypedArray, to be re-used by a later caller. After calling 1134 * this function you must not ever touch the typed array again. 1135 * 1136 * @throws RuntimeException if the TypedArray has already been recycled. 1137 */ recycle()1138 public void recycle() { 1139 if (mRecycled) { 1140 throw new RuntimeException(toString() + " recycled twice!"); 1141 } 1142 1143 mRecycled = true; 1144 1145 // These may have been set by the client. 1146 mXml = null; 1147 mTheme = null; 1148 mAssets = null; 1149 1150 mResources.mTypedArrayPool.release(this); 1151 } 1152 1153 /** 1154 * Extracts theme attributes from a typed array for later resolution using 1155 * {@link android.content.res.Resources.Theme#resolveAttributes(int[], int[])}. 1156 * Removes the entries from the typed array so that subsequent calls to typed 1157 * getters will return the default value without crashing. 1158 * 1159 * @return an array of length {@link #getIndexCount()} populated with theme 1160 * attributes, or null if there are no theme attributes in the typed 1161 * array 1162 * @throws RuntimeException if the TypedArray has already been recycled. 1163 * @hide 1164 */ 1165 @Nullable extractThemeAttrs()1166 public int[] extractThemeAttrs() { 1167 return extractThemeAttrs(null); 1168 } 1169 1170 /** 1171 * @hide 1172 */ 1173 @Nullable extractThemeAttrs(@ullable int[] scrap)1174 public int[] extractThemeAttrs(@Nullable int[] scrap) { 1175 if (mRecycled) { 1176 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1177 } 1178 1179 int[] attrs = null; 1180 1181 final int[] data = mData; 1182 final int N = length(); 1183 for (int i = 0; i < N; i++) { 1184 final int index = i * AssetManager.STYLE_NUM_ENTRIES; 1185 if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) { 1186 // Not an attribute, ignore. 1187 continue; 1188 } 1189 1190 // Null the entry so that we can safely call getZzz(). 1191 data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL; 1192 1193 final int attr = data[index + AssetManager.STYLE_DATA]; 1194 if (attr == 0) { 1195 // Useless data, ignore. 1196 continue; 1197 } 1198 1199 // Ensure we have a usable attribute array. 1200 if (attrs == null) { 1201 if (scrap != null && scrap.length == N) { 1202 attrs = scrap; 1203 Arrays.fill(attrs, 0); 1204 } else { 1205 attrs = new int[N]; 1206 } 1207 } 1208 1209 attrs[i] = attr; 1210 } 1211 1212 return attrs; 1213 } 1214 1215 /** 1216 * Return a mask of the configuration parameters for which the values in 1217 * this typed array may change. 1218 * 1219 * @return Returns a mask of the changing configuration parameters, as 1220 * defined by {@link android.content.pm.ActivityInfo}. 1221 * @throws RuntimeException if the TypedArray has already been recycled. 1222 * @see android.content.pm.ActivityInfo 1223 */ getChangingConfigurations()1224 public @Config int getChangingConfigurations() { 1225 if (mRecycled) { 1226 throw new RuntimeException("Cannot make calls to a recycled instance!"); 1227 } 1228 1229 @Config int changingConfig = 0; 1230 1231 final int[] data = mData; 1232 final int N = length(); 1233 for (int i = 0; i < N; i++) { 1234 final int index = i * AssetManager.STYLE_NUM_ENTRIES; 1235 final int type = data[index + AssetManager.STYLE_TYPE]; 1236 if (type == TypedValue.TYPE_NULL) { 1237 continue; 1238 } 1239 changingConfig |= ActivityInfo.activityInfoConfigNativeToJava( 1240 data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]); 1241 } 1242 return changingConfig; 1243 } 1244 getValueAt(int index, TypedValue outValue)1245 private boolean getValueAt(int index, TypedValue outValue) { 1246 final int[] data = mData; 1247 final int type = data[index+AssetManager.STYLE_TYPE]; 1248 if (type == TypedValue.TYPE_NULL) { 1249 return false; 1250 } 1251 outValue.type = type; 1252 outValue.data = data[index+AssetManager.STYLE_DATA]; 1253 outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 1254 outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID]; 1255 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 1256 data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]); 1257 outValue.density = data[index+AssetManager.STYLE_DENSITY]; 1258 outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null; 1259 return true; 1260 } 1261 loadStringValueAt(int index)1262 private CharSequence loadStringValueAt(int index) { 1263 final int[] data = mData; 1264 final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; 1265 if (cookie < 0) { 1266 if (mXml != null) { 1267 return mXml.getPooledString( 1268 data[index+AssetManager.STYLE_DATA]); 1269 } 1270 return null; 1271 } 1272 return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]); 1273 } 1274 1275 /** @hide */ TypedArray(Resources resources)1276 protected TypedArray(Resources resources) { 1277 mResources = resources; 1278 mMetrics = mResources.getDisplayMetrics(); 1279 mAssets = mResources.getAssets(); 1280 } 1281 1282 @Override toString()1283 public String toString() { 1284 return Arrays.toString(mData); 1285 } 1286 } 1287