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 com.android.layoutlib.bridge.android; 18 19 import com.android.ide.common.rendering.api.ILayoutPullParser; 20 import com.android.ide.common.rendering.api.IProjectCallback; 21 import com.android.ide.common.rendering.api.LayoutLog; 22 import com.android.ide.common.rendering.api.RenderResources; 23 import com.android.ide.common.rendering.api.ResourceReference; 24 import com.android.ide.common.rendering.api.ResourceValue; 25 import com.android.ide.common.rendering.api.StyleResourceValue; 26 import com.android.layoutlib.bridge.Bridge; 27 import com.android.layoutlib.bridge.BridgeConstants; 28 import com.android.layoutlib.bridge.impl.ParserFactory; 29 import com.android.layoutlib.bridge.impl.Stack; 30 import com.android.resources.ResourceType; 31 import com.android.util.Pair; 32 33 import org.xmlpull.v1.XmlPullParser; 34 import org.xmlpull.v1.XmlPullParserException; 35 36 import android.content.BroadcastReceiver; 37 import android.content.ComponentName; 38 import android.content.ContentResolver; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.content.IntentSender; 43 import android.content.ServiceConnection; 44 import android.content.SharedPreferences; 45 import android.content.pm.ApplicationInfo; 46 import android.content.pm.PackageManager; 47 import android.content.res.AssetManager; 48 import android.content.res.BridgeResources; 49 import android.content.res.BridgeTypedArray; 50 import android.content.res.Configuration; 51 import android.content.res.Resources; 52 import android.content.res.Resources.Theme; 53 import android.content.res.TypedArray; 54 import android.database.DatabaseErrorHandler; 55 import android.database.sqlite.SQLiteDatabase; 56 import android.database.sqlite.SQLiteDatabase.CursorFactory; 57 import android.graphics.Bitmap; 58 import android.graphics.drawable.Drawable; 59 import android.net.Uri; 60 import android.os.Bundle; 61 import android.os.Handler; 62 import android.os.Looper; 63 import android.util.AttributeSet; 64 import android.util.DisplayMetrics; 65 import android.util.TypedValue; 66 import android.view.BridgeInflater; 67 import android.view.Surface; 68 import android.view.View; 69 import android.view.ViewGroup; 70 import android.view.textservice.TextServicesManager; 71 72 import java.io.File; 73 import java.io.FileInputStream; 74 import java.io.FileNotFoundException; 75 import java.io.FileOutputStream; 76 import java.io.IOException; 77 import java.io.InputStream; 78 import java.util.HashMap; 79 import java.util.IdentityHashMap; 80 import java.util.Map; 81 import java.util.Map.Entry; 82 import java.util.TreeMap; 83 import java.util.concurrent.atomic.AtomicBoolean; 84 import java.util.concurrent.atomic.AtomicReference; 85 86 /** 87 * Custom implementation of Context/Activity to handle non compiled resources. 88 */ 89 public final class BridgeContext extends Context { 90 91 private Resources mSystemResources; 92 private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>(); 93 private final Object mProjectKey; 94 private final DisplayMetrics mMetrics; 95 private final RenderResources mRenderResources; 96 private final Configuration mConfig; 97 private final ApplicationInfo mApplicationInfo; 98 private final IProjectCallback mProjectCallback; 99 private final BridgeWindowManager mIWindowManager; 100 101 private Resources.Theme mTheme; 102 103 private final Map<Object, Map<String, String>> mDefaultPropMaps = 104 new IdentityHashMap<Object, Map<String,String>>(); 105 106 // maps for dynamically generated id representing style objects (StyleResourceValue) 107 private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap; 108 private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap; 109 private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style 110 111 // cache for TypedArray generated from IStyleResourceValue object 112 private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache; 113 private BridgeInflater mBridgeInflater; 114 115 private BridgeContentResolver mContentResolver; 116 117 private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>(); 118 119 /** 120 * @param projectKey An Object identifying the project. This is used for the cache mechanism. 121 * @param metrics the {@link DisplayMetrics}. 122 * @param renderResources the configured resources (both framework and projects) for this 123 * render. 124 * @param projectCallback 125 * @param config the Configuration object for this render. 126 * @param targetSdkVersion the targetSdkVersion of the application. 127 */ 128 public BridgeContext(Object projectKey, DisplayMetrics metrics, 129 RenderResources renderResources, 130 IProjectCallback projectCallback, 131 Configuration config, 132 int targetSdkVersion) { 133 mProjectKey = projectKey; 134 mMetrics = metrics; 135 mProjectCallback = projectCallback; 136 137 mRenderResources = renderResources; 138 mConfig = config; 139 140 mIWindowManager = new BridgeWindowManager(mConfig, metrics, Surface.ROTATION_0); 141 142 mApplicationInfo = new ApplicationInfo(); 143 mApplicationInfo.targetSdkVersion = targetSdkVersion; 144 } 145 146 /** 147 * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its 148 * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}. 149 * 150 * @see #disposeResources() 151 */ 152 public void initResources() { 153 AssetManager assetManager = AssetManager.getSystem(); 154 155 mSystemResources = BridgeResources.initSystem( 156 this, 157 assetManager, 158 mMetrics, 159 mConfig, 160 mProjectCallback); 161 mTheme = mSystemResources.newTheme(); 162 } 163 164 /** 165 * Disposes the {@link Resources} singleton. 166 */ 167 public void disposeResources() { 168 BridgeResources.disposeSystem(); 169 } 170 171 public void setBridgeInflater(BridgeInflater inflater) { 172 mBridgeInflater = inflater; 173 } 174 175 public void addViewKey(View view, Object viewKey) { 176 mViewKeyMap.put(view, viewKey); 177 } 178 179 public Object getViewKey(View view) { 180 return mViewKeyMap.get(view); 181 } 182 183 public Object getProjectKey() { 184 return mProjectKey; 185 } 186 187 public DisplayMetrics getMetrics() { 188 return mMetrics; 189 } 190 191 public IProjectCallback getProjectCallback() { 192 return mProjectCallback; 193 } 194 195 public RenderResources getRenderResources() { 196 return mRenderResources; 197 } 198 199 public BridgeWindowManager getIWindowManager() { 200 return mIWindowManager; 201 } 202 203 public Map<String, String> getDefaultPropMap(Object key) { 204 return mDefaultPropMaps.get(key); 205 } 206 207 /** 208 * Adds a parser to the stack. 209 * @param parser the parser to add. 210 */ 211 public void pushParser(BridgeXmlBlockParser parser) { 212 if (ParserFactory.LOG_PARSER) { 213 System.out.println("PUSH " + parser.getParser().toString()); 214 } 215 mParserStack.push(parser); 216 } 217 218 /** 219 * Removes the parser at the top of the stack 220 */ 221 public void popParser() { 222 BridgeXmlBlockParser parser = mParserStack.pop(); 223 if (ParserFactory.LOG_PARSER) { 224 System.out.println("POPD " + parser.getParser().toString()); 225 } 226 } 227 228 /** 229 * Returns the current parser at the top the of the stack. 230 * @return a parser or null. 231 */ 232 public BridgeXmlBlockParser getCurrentParser() { 233 return mParserStack.peek(); 234 } 235 236 /** 237 * Returns the previous parser. 238 * @return a parser or null if there isn't any previous parser 239 */ 240 public BridgeXmlBlockParser getPreviousParser() { 241 if (mParserStack.size() < 2) { 242 return null; 243 } 244 return mParserStack.get(mParserStack.size() - 2); 245 } 246 247 public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 248 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid); 249 if (resourceInfo == null) { 250 resourceInfo = mProjectCallback.resolveResourceId(resid); 251 } 252 253 if (resourceInfo == null) { 254 return false; 255 } 256 257 ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond()); 258 if (resolveRefs) { 259 value = mRenderResources.resolveResValue(value); 260 } 261 262 // check if this is a style resource 263 if (value instanceof StyleResourceValue) { 264 // get the id that will represent this style. 265 outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value); 266 return true; 267 } 268 269 270 int a; 271 // if this is a framework value. 272 if (value.isFramework()) { 273 // look for idName in the android R classes. 274 // use 0 a default res value as it's not a valid id value. 275 a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 276 } else { 277 // look for idName in the project R class. 278 // use 0 a default res value as it's not a valid id value. 279 a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 280 } 281 282 if (a != 0) { 283 outValue.resourceId = a; 284 return true; 285 } 286 287 return false; 288 } 289 290 291 public ResourceReference resolveId(int id) { 292 // first get the String related to this id in the framework 293 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id); 294 295 if (resourceInfo != null) { 296 return new ResourceReference(resourceInfo.getSecond(), true); 297 } 298 299 // didn't find a match in the framework? look in the project. 300 if (mProjectCallback != null) { 301 resourceInfo = mProjectCallback.resolveResourceId(id); 302 303 if (resourceInfo != null) { 304 return new ResourceReference(resourceInfo.getSecond(), false); 305 } 306 } 307 308 return null; 309 } 310 311 public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent, 312 boolean attachToRoot, boolean skipCallbackParser) { 313 boolean isPlatformLayout = resource.isFramework(); 314 315 if (isPlatformLayout == false && skipCallbackParser == false) { 316 // check if the project callback can provide us with a custom parser. 317 ILayoutPullParser parser; 318 if (resource instanceof ResourceValue) { 319 parser = mProjectCallback.getParser((ResourceValue) resource); 320 } else { 321 parser = mProjectCallback.getParser(resource.getName()); 322 } 323 324 if (parser != null) { 325 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 326 this, resource.isFramework()); 327 try { 328 pushParser(blockParser); 329 return Pair.of( 330 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 331 true); 332 } finally { 333 popParser(); 334 } 335 } 336 } 337 338 ResourceValue resValue; 339 if (resource instanceof ResourceValue) { 340 resValue = (ResourceValue) resource; 341 } else { 342 if (isPlatformLayout) { 343 resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT, 344 resource.getName()); 345 } else { 346 resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT, 347 resource.getName()); 348 } 349 } 350 351 if (resValue != null) { 352 353 File xml = new File(resValue.getValue()); 354 if (xml.isFile()) { 355 // we need to create a pull parser around the layout XML file, and then 356 // give that to our XmlBlockParser 357 try { 358 XmlPullParser parser = ParserFactory.create(xml); 359 360 // set the resource ref to have correct view cookies 361 mBridgeInflater.setResourceReference(resource); 362 363 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 364 this, resource.isFramework()); 365 try { 366 pushParser(blockParser); 367 return Pair.of( 368 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 369 false); 370 } finally { 371 popParser(); 372 } 373 } catch (XmlPullParserException e) { 374 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 375 "Failed to configure parser for " + xml, e, null /*data*/); 376 // we'll return null below. 377 } catch (FileNotFoundException e) { 378 // this shouldn't happen since we check above. 379 } finally { 380 mBridgeInflater.setResourceReference(null); 381 } 382 } else { 383 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 384 String.format("File %s is missing!", xml), null); 385 } 386 } else { 387 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 388 String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "", 389 resource.getName()), null); 390 } 391 392 return Pair.of(null, false); 393 } 394 395 // ------------ Context methods 396 397 @Override 398 public Resources getResources() { 399 return mSystemResources; 400 } 401 402 @Override 403 public Theme getTheme() { 404 return mTheme; 405 } 406 407 @Override 408 public ClassLoader getClassLoader() { 409 return this.getClass().getClassLoader(); 410 } 411 412 @Override 413 public Object getSystemService(String service) { 414 if (LAYOUT_INFLATER_SERVICE.equals(service)) { 415 return mBridgeInflater; 416 } 417 418 if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) { 419 // we need to return a valid service to avoid NPE 420 return TextServicesManager.getInstance(); 421 } 422 423 // AutoCompleteTextView and MultiAutoCompleteTextView want a window 424 // service. We don't have any but it's not worth an exception. 425 if (WINDOW_SERVICE.equals(service)) { 426 return null; 427 } 428 429 // needed by SearchView 430 if (INPUT_METHOD_SERVICE.equals(service)) { 431 return null; 432 } 433 434 throw new UnsupportedOperationException("Unsupported Service: " + service); 435 } 436 437 438 @Override 439 public final TypedArray obtainStyledAttributes(int[] attrs) { 440 return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs); 441 } 442 443 @Override 444 public final TypedArray obtainStyledAttributes(int resid, int[] attrs) 445 throws Resources.NotFoundException { 446 // get the StyleResourceValue based on the resId; 447 StyleResourceValue style = getStyleByDynamicId(resid); 448 449 if (style == null) { 450 throw new Resources.NotFoundException(); 451 } 452 453 if (mTypedArrayCache == null) { 454 mTypedArrayCache = new HashMap<int[], Map<Integer,TypedArray>>(); 455 456 Map<Integer, TypedArray> map = new HashMap<Integer, TypedArray>(); 457 mTypedArrayCache.put(attrs, map); 458 459 BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs); 460 map.put(resid, ta); 461 462 return ta; 463 } 464 465 // get the 2nd map 466 Map<Integer, TypedArray> map = mTypedArrayCache.get(attrs); 467 if (map == null) { 468 map = new HashMap<Integer, TypedArray>(); 469 mTypedArrayCache.put(attrs, map); 470 } 471 472 // get the array from the 2nd map 473 TypedArray ta = map.get(resid); 474 475 if (ta == null) { 476 ta = createStyleBasedTypedArray(style, attrs); 477 map.put(resid, ta); 478 } 479 480 return ta; 481 } 482 483 @Override 484 public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { 485 return obtainStyledAttributes(set, attrs, 0, 0); 486 } 487 488 @Override 489 public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, 490 int defStyleAttr, int defStyleRes) { 491 492 Map<String, String> defaultPropMap = null; 493 boolean isPlatformFile = true; 494 495 // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java 496 if (set instanceof BridgeXmlBlockParser) { 497 BridgeXmlBlockParser parser = null; 498 parser = (BridgeXmlBlockParser)set; 499 500 isPlatformFile = parser.isPlatformFile(); 501 502 Object key = parser.getViewCookie(); 503 if (key != null) { 504 defaultPropMap = mDefaultPropMaps.get(key); 505 if (defaultPropMap == null) { 506 defaultPropMap = new HashMap<String, String>(); 507 mDefaultPropMaps.put(key, defaultPropMap); 508 } 509 } 510 511 } else if (set instanceof BridgeLayoutParamsMapAttributes) { 512 // this is only for temp layout params generated dynamically, so this is never 513 // platform content. 514 isPlatformFile = false; 515 } else if (set != null) { // null parser is ok 516 // really this should not be happening since its instantiated in Bridge 517 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 518 "Parser is not a BridgeXmlBlockParser!", null /*data*/); 519 return null; 520 } 521 522 AtomicBoolean frameworkAttributes = new AtomicBoolean(); 523 AtomicReference<String> attrName = new AtomicReference<String>(); 524 TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes, attrName); 525 526 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 527 isPlatformFile, frameworkAttributes.get(), attrName.get()); 528 529 // look for a custom style. 530 String customStyle = null; 531 if (set != null) { 532 customStyle = set.getAttributeValue(null /* namespace*/, "style"); 533 } 534 535 StyleResourceValue customStyleValues = null; 536 if (customStyle != null) { 537 ResourceValue item = mRenderResources.findResValue(customStyle, 538 false /*forceFrameworkOnly*/); 539 540 // resolve it in case it links to something else 541 item = mRenderResources.resolveResValue(item); 542 543 if (item instanceof StyleResourceValue) { 544 customStyleValues = (StyleResourceValue)item; 545 } 546 } 547 548 // resolve the defStyleAttr value into a IStyleResourceValue 549 StyleResourceValue defStyleValues = null; 550 551 if (defStyleAttr != 0) { 552 // get the name from the int. 553 String defStyleName = searchAttr(defStyleAttr); 554 555 if (defaultPropMap != null) { 556 defaultPropMap.put("style", defStyleName); 557 } 558 559 // look for the style in the current theme, and its parent: 560 ResourceValue item = mRenderResources.findItemInTheme(defStyleName); 561 562 if (item != null) { 563 // item is a reference to a style entry. Search for it. 564 item = mRenderResources.findResValue(item.getValue(), 565 false /*forceFrameworkOnly*/); 566 567 if (item instanceof StyleResourceValue) { 568 defStyleValues = (StyleResourceValue)item; 569 } 570 } else { 571 Bridge.getLog().error(null, 572 String.format( 573 "Failed to find style '%s' in current theme", defStyleName), 574 null /*data*/); 575 } 576 } else if (defStyleRes != 0) { 577 Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); 578 if (value == null) { 579 value = mProjectCallback.resolveResourceId(defStyleRes); 580 } 581 582 if (value != null) { 583 if (value.getFirst() == ResourceType.STYLE) { 584 // look for the style in the current theme, and its parent: 585 ResourceValue item = mRenderResources.findItemInTheme(value.getSecond()); 586 if (item != null) { 587 if (item instanceof StyleResourceValue) { 588 if (defaultPropMap != null) { 589 defaultPropMap.put("style", item.getName()); 590 } 591 592 defStyleValues = (StyleResourceValue)item; 593 } 594 } else { 595 Bridge.getLog().error(null, 596 String.format( 597 "Style with id 0x%x (resolved to '%s') does not exist.", 598 defStyleRes, value.getSecond()), 599 null /*data*/); 600 } 601 } else { 602 Bridge.getLog().error(null, 603 String.format( 604 "Resouce id 0x%x is not of type STYLE (instead %s)", 605 defStyleRes, value.getFirst().toString()), 606 null /*data*/); 607 } 608 } else { 609 Bridge.getLog().error(null, 610 String.format( 611 "Failed to find style with id 0x%x in current theme", 612 defStyleRes), 613 null /*data*/); 614 } 615 } 616 617 String namespace = BridgeConstants.NS_RESOURCES; 618 boolean useFrameworkNS = frameworkAttributes.get(); 619 if (useFrameworkNS == false) { 620 // need to use the application namespace 621 namespace = mProjectCallback.getNamespace(); 622 } 623 624 if (styleNameMap != null) { 625 for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) { 626 int index = styleAttribute.getKey().intValue(); 627 628 String name = styleAttribute.getValue(); 629 String value = null; 630 if (set != null) { 631 value = set.getAttributeValue(namespace, name); 632 633 // if this is an app attribute, and the first get fails, try with the 634 // new res-auto namespace as well 635 if (useFrameworkNS == false && value == null) { 636 value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, name); 637 } 638 } 639 640 // if there's no direct value for this attribute in the XML, we look for default 641 // values in the widget defStyle, and then in the theme. 642 if (value == null) { 643 ResourceValue resValue = null; 644 645 // look for the value in the custom style first (and its parent if needed) 646 if (customStyleValues != null) { 647 resValue = mRenderResources.findItemInStyle(customStyleValues, name); 648 } 649 650 // then look for the value in the default Style (and its parent if needed) 651 if (resValue == null && defStyleValues != null) { 652 resValue = mRenderResources.findItemInStyle(defStyleValues, name); 653 } 654 655 // if the item is not present in the defStyle, we look in the main theme (and 656 // its parent themes) 657 if (resValue == null) { 658 resValue = mRenderResources.findItemInTheme(name); 659 } 660 661 // if we found a value, we make sure this doesn't reference another value. 662 // So we resolve it. 663 if (resValue != null) { 664 // put the first default value, before the resolution. 665 if (defaultPropMap != null) { 666 defaultPropMap.put(name, resValue.getValue()); 667 } 668 669 resValue = mRenderResources.resolveResValue(resValue); 670 } 671 672 ta.bridgeSetValue(index, name, resValue); 673 } else { 674 // there is a value in the XML, but we need to resolve it in case it's 675 // referencing another resource or a theme value. 676 ta.bridgeSetValue(index, name, 677 mRenderResources.resolveValue(null, name, value, isPlatformFile)); 678 } 679 } 680 } 681 682 ta.sealArray(); 683 684 return ta; 685 } 686 687 @Override 688 public Looper getMainLooper() { 689 return Looper.myLooper(); 690 } 691 692 693 // ------------- private new methods 694 695 /** 696 * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the 697 * values found in the given style. 698 * @see #obtainStyledAttributes(int, int[]) 699 */ 700 private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs) 701 throws Resources.NotFoundException { 702 703 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 704 false, true, null); 705 706 // for each attribute, get its name so that we can search it in the style 707 for (int i = 0 ; i < attrs.length ; i++) { 708 Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]); 709 if (resolvedResource != null) { 710 String attrName = resolvedResource.getSecond(); 711 // look for the value in the given style 712 ResourceValue resValue = mRenderResources.findItemInStyle(style, attrName); 713 714 if (resValue != null) { 715 // resolve it to make sure there are no references left. 716 ta.bridgeSetValue(i, attrName, mRenderResources.resolveResValue(resValue)); 717 718 resValue = mRenderResources.resolveResValue(resValue); 719 } 720 } 721 } 722 723 ta.sealArray(); 724 725 return ta; 726 } 727 728 729 /** 730 * The input int[] attrs is one of com.android.internal.R.styleable fields where the name 731 * of the field is the style being referenced and the array contains one index per attribute. 732 * <p/> 733 * searchAttrs() finds all the names of the attributes referenced so for example if 734 * attrs == com.android.internal.R.styleable.View, this returns the list of the "xyz" where 735 * there's a field com.android.internal.R.styleable.View_xyz and the field value is the index 736 * that is used to reference the attribute later in the TypedArray. 737 * 738 * @param attrs An attribute array reference given to obtainStyledAttributes. 739 * @param outFrameworkFlag out value indicating if the attr array is a framework value 740 * @param outAttrName out value for the resolved attr name. 741 * @return A sorted map Attribute-Value to Attribute-Name for all attributes declared by the 742 * attribute array. Returns null if nothing is found. 743 */ 744 private TreeMap<Integer,String> searchAttrs(int[] attrs, AtomicBoolean outFrameworkFlag, 745 AtomicReference<String> outAttrName) { 746 // get the name of the array from the framework resources 747 String arrayName = Bridge.resolveResourceId(attrs); 748 if (arrayName != null) { 749 // if we found it, get the name of each of the int in the array. 750 TreeMap<Integer,String> attributes = new TreeMap<Integer, String>(); 751 for (int i = 0 ; i < attrs.length ; i++) { 752 Pair<ResourceType, String> info = Bridge.resolveResourceId(attrs[i]); 753 if (info != null) { 754 attributes.put(i, info.getSecond()); 755 } else { 756 // FIXME Not sure what we should be doing here... 757 attributes.put(i, null); 758 } 759 } 760 761 if (outFrameworkFlag != null) { 762 outFrameworkFlag.set(true); 763 } 764 if (outAttrName != null) { 765 outAttrName.set(arrayName); 766 } 767 768 return attributes; 769 } 770 771 // if the name was not found in the framework resources, look in the project 772 // resources 773 arrayName = mProjectCallback.resolveResourceId(attrs); 774 if (arrayName != null) { 775 TreeMap<Integer,String> attributes = new TreeMap<Integer, String>(); 776 for (int i = 0 ; i < attrs.length ; i++) { 777 Pair<ResourceType, String> info = mProjectCallback.resolveResourceId(attrs[i]); 778 if (info != null) { 779 attributes.put(i, info.getSecond()); 780 } else { 781 // FIXME Not sure what we should be doing here... 782 attributes.put(i, null); 783 } 784 } 785 786 if (outFrameworkFlag != null) { 787 outFrameworkFlag.set(false); 788 } 789 if (outAttrName != null) { 790 outAttrName.set(arrayName); 791 } 792 793 return attributes; 794 } 795 796 return null; 797 } 798 799 /** 800 * Searches for the attribute referenced by its internal id. 801 * 802 * @param attr An attribute reference given to obtainStyledAttributes such as defStyle. 803 * @return The unique name of the attribute, if found, e.g. "buttonStyle". Returns null 804 * if nothing is found. 805 */ 806 public String searchAttr(int attr) { 807 Pair<ResourceType, String> info = Bridge.resolveResourceId(attr); 808 if (info != null) { 809 return info.getSecond(); 810 } 811 812 info = mProjectCallback.resolveResourceId(attr); 813 if (info != null) { 814 return info.getSecond(); 815 } 816 817 return null; 818 } 819 820 public int getDynamicIdByStyle(StyleResourceValue resValue) { 821 if (mDynamicIdToStyleMap == null) { 822 // create the maps. 823 mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>(); 824 mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>(); 825 } 826 827 // look for an existing id 828 Integer id = mStyleToDynamicIdMap.get(resValue); 829 830 if (id == null) { 831 // generate a new id 832 id = Integer.valueOf(++mDynamicIdGenerator); 833 834 // and add it to the maps. 835 mDynamicIdToStyleMap.put(id, resValue); 836 mStyleToDynamicIdMap.put(resValue, id); 837 } 838 839 return id; 840 } 841 842 private StyleResourceValue getStyleByDynamicId(int i) { 843 if (mDynamicIdToStyleMap != null) { 844 return mDynamicIdToStyleMap.get(i); 845 } 846 847 return null; 848 } 849 850 public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) { 851 Integer value = Bridge.getResourceId(resType, resName); 852 if (value != null) { 853 return value.intValue(); 854 } 855 856 return defValue; 857 } 858 859 public int getProjectResourceValue(ResourceType resType, String resName, int defValue) { 860 if (mProjectCallback != null) { 861 Integer value = mProjectCallback.getResourceId(resType, resName); 862 if (value != null) { 863 return value.intValue(); 864 } 865 } 866 867 return defValue; 868 } 869 870 //------------ NOT OVERRIDEN -------------------- 871 872 @Override 873 public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) { 874 // TODO Auto-generated method stub 875 return false; 876 } 877 878 @Override 879 public int checkCallingOrSelfPermission(String arg0) { 880 // TODO Auto-generated method stub 881 return 0; 882 } 883 884 @Override 885 public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) { 886 // TODO Auto-generated method stub 887 return 0; 888 } 889 890 @Override 891 public int checkCallingPermission(String arg0) { 892 // TODO Auto-generated method stub 893 return 0; 894 } 895 896 @Override 897 public int checkCallingUriPermission(Uri arg0, int arg1) { 898 // TODO Auto-generated method stub 899 return 0; 900 } 901 902 @Override 903 public int checkPermission(String arg0, int arg1, int arg2) { 904 // TODO Auto-generated method stub 905 return 0; 906 } 907 908 @Override 909 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) { 910 // TODO Auto-generated method stub 911 return 0; 912 } 913 914 @Override 915 public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3, 916 int arg4, int arg5) { 917 // TODO Auto-generated method stub 918 return 0; 919 } 920 921 @Override 922 public void clearWallpaper() { 923 // TODO Auto-generated method stub 924 925 } 926 927 @Override 928 public Context createPackageContext(String arg0, int arg1) { 929 // TODO Auto-generated method stub 930 return null; 931 } 932 933 @Override 934 public String[] databaseList() { 935 // TODO Auto-generated method stub 936 return null; 937 } 938 939 @Override 940 public boolean deleteDatabase(String arg0) { 941 // TODO Auto-generated method stub 942 return false; 943 } 944 945 @Override 946 public boolean deleteFile(String arg0) { 947 // TODO Auto-generated method stub 948 return false; 949 } 950 951 @Override 952 public void enforceCallingOrSelfPermission(String arg0, String arg1) { 953 // TODO Auto-generated method stub 954 955 } 956 957 @Override 958 public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1, 959 String arg2) { 960 // TODO Auto-generated method stub 961 962 } 963 964 @Override 965 public void enforceCallingPermission(String arg0, String arg1) { 966 // TODO Auto-generated method stub 967 968 } 969 970 @Override 971 public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) { 972 // TODO Auto-generated method stub 973 974 } 975 976 @Override 977 public void enforcePermission(String arg0, int arg1, int arg2, String arg3) { 978 // TODO Auto-generated method stub 979 980 } 981 982 @Override 983 public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3, 984 String arg4) { 985 // TODO Auto-generated method stub 986 987 } 988 989 @Override 990 public void enforceUriPermission(Uri arg0, String arg1, String arg2, 991 int arg3, int arg4, int arg5, String arg6) { 992 // TODO Auto-generated method stub 993 994 } 995 996 @Override 997 public String[] fileList() { 998 // TODO Auto-generated method stub 999 return null; 1000 } 1001 1002 @Override 1003 public AssetManager getAssets() { 1004 // TODO Auto-generated method stub 1005 return null; 1006 } 1007 1008 @Override 1009 public File getCacheDir() { 1010 // TODO Auto-generated method stub 1011 return null; 1012 } 1013 1014 @Override 1015 public File getExternalCacheDir() { 1016 // TODO Auto-generated method stub 1017 return null; 1018 } 1019 1020 @Override 1021 public ContentResolver getContentResolver() { 1022 if (mContentResolver == null) { 1023 mContentResolver = new BridgeContentResolver(this); 1024 } 1025 return mContentResolver; 1026 } 1027 1028 @Override 1029 public File getDatabasePath(String arg0) { 1030 // TODO Auto-generated method stub 1031 return null; 1032 } 1033 1034 @Override 1035 public File getDir(String arg0, int arg1) { 1036 // TODO Auto-generated method stub 1037 return null; 1038 } 1039 1040 @Override 1041 public File getFileStreamPath(String arg0) { 1042 // TODO Auto-generated method stub 1043 return null; 1044 } 1045 1046 @Override 1047 public File getFilesDir() { 1048 // TODO Auto-generated method stub 1049 return null; 1050 } 1051 1052 @Override 1053 public File getExternalFilesDir(String type) { 1054 // TODO Auto-generated method stub 1055 return null; 1056 } 1057 1058 @Override 1059 public String getPackageCodePath() { 1060 // TODO Auto-generated method stub 1061 return null; 1062 } 1063 1064 @Override 1065 public PackageManager getPackageManager() { 1066 // TODO Auto-generated method stub 1067 return null; 1068 } 1069 1070 @Override 1071 public String getPackageName() { 1072 // TODO Auto-generated method stub 1073 return null; 1074 } 1075 1076 @Override 1077 public ApplicationInfo getApplicationInfo() { 1078 return mApplicationInfo; 1079 } 1080 1081 @Override 1082 public String getPackageResourcePath() { 1083 // TODO Auto-generated method stub 1084 return null; 1085 } 1086 1087 @Override 1088 public File getSharedPrefsFile(String name) { 1089 // TODO Auto-generated method stub 1090 return null; 1091 } 1092 1093 @Override 1094 public SharedPreferences getSharedPreferences(String arg0, int arg1) { 1095 // TODO Auto-generated method stub 1096 return null; 1097 } 1098 1099 @Override 1100 public Drawable getWallpaper() { 1101 // TODO Auto-generated method stub 1102 return null; 1103 } 1104 1105 @Override 1106 public int getWallpaperDesiredMinimumWidth() { 1107 return -1; 1108 } 1109 1110 @Override 1111 public int getWallpaperDesiredMinimumHeight() { 1112 return -1; 1113 } 1114 1115 @Override 1116 public void grantUriPermission(String arg0, Uri arg1, int arg2) { 1117 // TODO Auto-generated method stub 1118 1119 } 1120 1121 @Override 1122 public FileInputStream openFileInput(String arg0) throws FileNotFoundException { 1123 // TODO Auto-generated method stub 1124 return null; 1125 } 1126 1127 @Override 1128 public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException { 1129 // TODO Auto-generated method stub 1130 return null; 1131 } 1132 1133 @Override 1134 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) { 1135 // TODO Auto-generated method stub 1136 return null; 1137 } 1138 1139 @Override 1140 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, 1141 CursorFactory arg2, DatabaseErrorHandler arg3) { 1142 // TODO Auto-generated method stub 1143 return null; 1144 } 1145 1146 @Override 1147 public Drawable peekWallpaper() { 1148 // TODO Auto-generated method stub 1149 return null; 1150 } 1151 1152 @Override 1153 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) { 1154 // TODO Auto-generated method stub 1155 return null; 1156 } 1157 1158 @Override 1159 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, 1160 String arg2, Handler arg3) { 1161 // TODO Auto-generated method stub 1162 return null; 1163 } 1164 1165 @Override 1166 public void removeStickyBroadcast(Intent arg0) { 1167 // TODO Auto-generated method stub 1168 1169 } 1170 1171 @Override 1172 public void revokeUriPermission(Uri arg0, int arg1) { 1173 // TODO Auto-generated method stub 1174 1175 } 1176 1177 @Override 1178 public void sendBroadcast(Intent arg0) { 1179 // TODO Auto-generated method stub 1180 1181 } 1182 1183 @Override 1184 public void sendBroadcast(Intent arg0, String arg1) { 1185 // TODO Auto-generated method stub 1186 1187 } 1188 1189 @Override 1190 public void sendOrderedBroadcast(Intent arg0, String arg1) { 1191 // TODO Auto-generated method stub 1192 1193 } 1194 1195 @Override 1196 public void sendOrderedBroadcast(Intent arg0, String arg1, 1197 BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, 1198 Bundle arg6) { 1199 // TODO Auto-generated method stub 1200 1201 } 1202 1203 @Override 1204 public void sendStickyBroadcast(Intent arg0) { 1205 // TODO Auto-generated method stub 1206 1207 } 1208 1209 @Override 1210 public void sendStickyOrderedBroadcast(Intent intent, 1211 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, 1212 Bundle initialExtras) { 1213 // TODO Auto-generated method stub 1214 } 1215 1216 @Override 1217 public void setTheme(int arg0) { 1218 // TODO Auto-generated method stub 1219 1220 } 1221 1222 @Override 1223 public void setWallpaper(Bitmap arg0) throws IOException { 1224 // TODO Auto-generated method stub 1225 1226 } 1227 1228 @Override 1229 public void setWallpaper(InputStream arg0) throws IOException { 1230 // TODO Auto-generated method stub 1231 1232 } 1233 1234 @Override 1235 public void startActivity(Intent arg0) { 1236 // TODO Auto-generated method stub 1237 1238 } 1239 1240 @Override 1241 public void startIntentSender(IntentSender intent, 1242 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) 1243 throws IntentSender.SendIntentException { 1244 // TODO Auto-generated method stub 1245 } 1246 1247 @Override 1248 public boolean startInstrumentation(ComponentName arg0, String arg1, 1249 Bundle arg2) { 1250 // TODO Auto-generated method stub 1251 return false; 1252 } 1253 1254 @Override 1255 public ComponentName startService(Intent arg0) { 1256 // TODO Auto-generated method stub 1257 return null; 1258 } 1259 1260 @Override 1261 public boolean stopService(Intent arg0) { 1262 // TODO Auto-generated method stub 1263 return false; 1264 } 1265 1266 @Override 1267 public void unbindService(ServiceConnection arg0) { 1268 // TODO Auto-generated method stub 1269 1270 } 1271 1272 @Override 1273 public void unregisterReceiver(BroadcastReceiver arg0) { 1274 // TODO Auto-generated method stub 1275 1276 } 1277 1278 @Override 1279 public Context getApplicationContext() { 1280 return this; 1281 } 1282 1283 @Override 1284 public void startActivities(Intent[] arg0) { 1285 // TODO Auto-generated method stub 1286 1287 } 1288 1289 @Override 1290 public boolean isRestricted() { 1291 return false; 1292 } 1293 1294 @Override 1295 public File getObbDir() { 1296 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null); 1297 return null; 1298 } 1299 } 1300