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