1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.layoutlib.bridge.android; 18 19import android.os.IBinder; 20import com.android.annotations.Nullable; 21import com.android.ide.common.rendering.api.ILayoutPullParser; 22import com.android.ide.common.rendering.api.IProjectCallback; 23import com.android.ide.common.rendering.api.LayoutLog; 24import com.android.ide.common.rendering.api.RenderResources; 25import com.android.ide.common.rendering.api.ResourceReference; 26import com.android.ide.common.rendering.api.ResourceValue; 27import com.android.ide.common.rendering.api.StyleResourceValue; 28import com.android.layoutlib.bridge.Bridge; 29import com.android.layoutlib.bridge.BridgeConstants; 30import com.android.layoutlib.bridge.android.view.WindowManagerImpl; 31import com.android.layoutlib.bridge.impl.ParserFactory; 32import com.android.layoutlib.bridge.impl.Stack; 33import com.android.resources.ResourceType; 34import com.android.util.Pair; 35 36import org.xmlpull.v1.XmlPullParser; 37import org.xmlpull.v1.XmlPullParserException; 38 39import android.content.BroadcastReceiver; 40import android.content.ComponentName; 41import android.content.ContentResolver; 42import android.content.Context; 43import android.content.Intent; 44import android.content.IntentFilter; 45import android.content.IntentSender; 46import android.content.ServiceConnection; 47import android.content.SharedPreferences; 48import android.content.pm.ApplicationInfo; 49import android.content.pm.PackageManager; 50import android.content.res.AssetManager; 51import android.content.res.BridgeResources; 52import android.content.res.BridgeTypedArray; 53import android.content.res.Configuration; 54import android.content.res.Resources; 55import android.content.res.Resources.Theme; 56import android.database.DatabaseErrorHandler; 57import android.database.sqlite.SQLiteDatabase; 58import android.database.sqlite.SQLiteDatabase.CursorFactory; 59import android.graphics.Bitmap; 60import android.graphics.drawable.Drawable; 61import android.hardware.display.DisplayManager; 62import android.net.Uri; 63import android.os.Bundle; 64import android.os.Handler; 65import android.os.Looper; 66import android.os.PowerManager; 67import android.os.UserHandle; 68import android.util.AttributeSet; 69import android.util.DisplayMetrics; 70import android.util.TypedValue; 71import android.view.BridgeInflater; 72import android.view.Display; 73import android.view.DisplayAdjustments; 74import android.view.View; 75import android.view.ViewGroup; 76import android.view.WindowManager; 77import android.view.accessibility.AccessibilityManager; 78import android.view.textservice.TextServicesManager; 79 80import java.io.File; 81import java.io.FileInputStream; 82import java.io.FileNotFoundException; 83import java.io.FileOutputStream; 84import java.io.IOException; 85import java.io.InputStream; 86import java.util.ArrayList; 87import java.util.HashMap; 88import java.util.IdentityHashMap; 89import java.util.List; 90import java.util.Map; 91 92/** 93 * Custom implementation of Context/Activity to handle non compiled resources. 94 */ 95public final class BridgeContext extends Context { 96 97 /** The map adds cookies to each view so that IDE can link xml tags to views. */ 98 private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>(); 99 /** 100 * In some cases, when inflating an xml, some objects are created. Then later, the objects are 101 * converted to views. This map stores the mapping from objects to cookies which can then be 102 * used to populate the mViewKeyMap. 103 */ 104 private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>(); 105 private Resources mSystemResources; 106 private final Object mProjectKey; 107 private final DisplayMetrics mMetrics; 108 private final RenderResources mRenderResources; 109 private final Configuration mConfig; 110 private final ApplicationInfo mApplicationInfo; 111 private final IProjectCallback mProjectCallback; 112 private final WindowManager mWindowManager; 113 private final DisplayManager mDisplayManager; 114 115 private Resources.Theme mTheme; 116 117 private final Map<Object, Map<String, String>> mDefaultPropMaps = 118 new IdentityHashMap<Object, Map<String,String>>(); 119 120 // maps for dynamically generated id representing style objects (StyleResourceValue) 121 private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap; 122 private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap; 123 private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace 124 125 // cache for TypedArray generated from IStyleResourceValue object 126 private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache; 127 private BridgeInflater mBridgeInflater; 128 129 private BridgeContentResolver mContentResolver; 130 131 private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>(); 132 private SharedPreferences mSharedPreferences; 133 134 /** 135 * @param projectKey An Object identifying the project. This is used for the cache mechanism. 136 * @param metrics the {@link DisplayMetrics}. 137 * @param renderResources the configured resources (both framework and projects) for this 138 * render. 139 * @param config the Configuration object for this render. 140 * @param targetSdkVersion the targetSdkVersion of the application. 141 */ 142 public BridgeContext(Object projectKey, DisplayMetrics metrics, 143 RenderResources renderResources, 144 IProjectCallback projectCallback, 145 Configuration config, 146 int targetSdkVersion, 147 boolean hasRtlSupport) { 148 mProjectKey = projectKey; 149 mMetrics = metrics; 150 mProjectCallback = projectCallback; 151 152 mRenderResources = renderResources; 153 mConfig = config; 154 155 mApplicationInfo = new ApplicationInfo(); 156 mApplicationInfo.targetSdkVersion = targetSdkVersion; 157 if (hasRtlSupport) { 158 mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL; 159 } 160 161 mWindowManager = new WindowManagerImpl(mMetrics); 162 mDisplayManager = new DisplayManager(this); 163 } 164 165 /** 166 * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its 167 * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}. 168 * 169 * @see #disposeResources() 170 */ 171 public void initResources() { 172 AssetManager assetManager = AssetManager.getSystem(); 173 174 mSystemResources = BridgeResources.initSystem( 175 this, 176 assetManager, 177 mMetrics, 178 mConfig, 179 mProjectCallback); 180 mTheme = mSystemResources.newTheme(); 181 } 182 183 /** 184 * Disposes the {@link Resources} singleton. 185 */ 186 public void disposeResources() { 187 BridgeResources.disposeSystem(); 188 } 189 190 public void setBridgeInflater(BridgeInflater inflater) { 191 mBridgeInflater = inflater; 192 } 193 194 public void addViewKey(View view, Object viewKey) { 195 mViewKeyMap.put(view, viewKey); 196 } 197 198 public Object getViewKey(View view) { 199 return mViewKeyMap.get(view); 200 } 201 202 public void addCookie(Object o, Object cookie) { 203 mViewKeyHelpMap.put(o, cookie); 204 } 205 206 public Object getCookie(Object o) { 207 return mViewKeyHelpMap.get(o); 208 } 209 210 public Object getProjectKey() { 211 return mProjectKey; 212 } 213 214 public DisplayMetrics getMetrics() { 215 return mMetrics; 216 } 217 218 public IProjectCallback getProjectCallback() { 219 return mProjectCallback; 220 } 221 222 public RenderResources getRenderResources() { 223 return mRenderResources; 224 } 225 226 public Map<String, String> getDefaultPropMap(Object key) { 227 return mDefaultPropMaps.get(key); 228 } 229 230 public Configuration getConfiguration() { 231 return mConfig; 232 } 233 234 /** 235 * Adds a parser to the stack. 236 * @param parser the parser to add. 237 */ 238 public void pushParser(BridgeXmlBlockParser parser) { 239 if (ParserFactory.LOG_PARSER) { 240 System.out.println("PUSH " + parser.getParser().toString()); 241 } 242 mParserStack.push(parser); 243 } 244 245 /** 246 * Removes the parser at the top of the stack 247 */ 248 public void popParser() { 249 BridgeXmlBlockParser parser = mParserStack.pop(); 250 if (ParserFactory.LOG_PARSER) { 251 System.out.println("POPD " + parser.getParser().toString()); 252 } 253 } 254 255 /** 256 * Returns the current parser at the top the of the stack. 257 * @return a parser or null. 258 */ 259 public BridgeXmlBlockParser getCurrentParser() { 260 return mParserStack.peek(); 261 } 262 263 /** 264 * Returns the previous parser. 265 * @return a parser or null if there isn't any previous parser 266 */ 267 public BridgeXmlBlockParser getPreviousParser() { 268 if (mParserStack.size() < 2) { 269 return null; 270 } 271 return mParserStack.get(mParserStack.size() - 2); 272 } 273 274 public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 275 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid); 276 boolean isFrameworkRes = true; 277 if (resourceInfo == null) { 278 resourceInfo = mProjectCallback.resolveResourceId(resid); 279 isFrameworkRes = false; 280 } 281 282 if (resourceInfo == null) { 283 return false; 284 } 285 286 ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(), 287 isFrameworkRes); 288 if (resolveRefs) { 289 value = mRenderResources.resolveResValue(value); 290 } 291 292 if (value == null) { 293 // unable to find the attribute. 294 return false; 295 } 296 297 // check if this is a style resource 298 if (value instanceof StyleResourceValue) { 299 // get the id that will represent this style. 300 outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value); 301 return true; 302 } 303 304 int a; 305 // if this is a framework value. 306 if (value.isFramework()) { 307 // look for idName in the android R classes. 308 // use 0 a default res value as it's not a valid id value. 309 a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 310 } else { 311 // look for idName in the project R class. 312 // use 0 a default res value as it's not a valid id value. 313 a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 314 } 315 316 if (a != 0) { 317 outValue.resourceId = a; 318 return true; 319 } 320 321 return false; 322 } 323 324 325 public ResourceReference resolveId(int id) { 326 // first get the String related to this id in the framework 327 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id); 328 329 if (resourceInfo != null) { 330 return new ResourceReference(resourceInfo.getSecond(), true); 331 } 332 333 // didn't find a match in the framework? look in the project. 334 if (mProjectCallback != null) { 335 resourceInfo = mProjectCallback.resolveResourceId(id); 336 337 if (resourceInfo != null) { 338 return new ResourceReference(resourceInfo.getSecond(), false); 339 } 340 } 341 342 // The base value for R.style is 0x01030000 and the custom style is 0x02030000. 343 // So, if the second byte is 03, it's probably a style. 344 if ((id >> 16 & 0xFF) == 0x03) { 345 return getStyleByDynamicId(id); 346 } 347 return null; 348 } 349 350 public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent, 351 boolean attachToRoot, boolean skipCallbackParser) { 352 boolean isPlatformLayout = resource.isFramework(); 353 354 if (!isPlatformLayout && !skipCallbackParser) { 355 // check if the project callback can provide us with a custom parser. 356 ILayoutPullParser parser = getParser(resource); 357 358 if (parser != null) { 359 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 360 this, resource.isFramework()); 361 try { 362 pushParser(blockParser); 363 return Pair.of( 364 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 365 true); 366 } finally { 367 popParser(); 368 } 369 } 370 } 371 372 ResourceValue resValue; 373 if (resource instanceof ResourceValue) { 374 resValue = (ResourceValue) resource; 375 } else { 376 if (isPlatformLayout) { 377 resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT, 378 resource.getName()); 379 } else { 380 resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT, 381 resource.getName()); 382 } 383 } 384 385 if (resValue != null) { 386 387 File xml = new File(resValue.getValue()); 388 if (xml.isFile()) { 389 // we need to create a pull parser around the layout XML file, and then 390 // give that to our XmlBlockParser 391 try { 392 XmlPullParser parser = ParserFactory.create(xml); 393 394 // set the resource ref to have correct view cookies 395 mBridgeInflater.setResourceReference(resource); 396 397 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 398 this, resource.isFramework()); 399 try { 400 pushParser(blockParser); 401 return Pair.of( 402 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 403 false); 404 } finally { 405 popParser(); 406 } 407 } catch (XmlPullParserException e) { 408 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 409 "Failed to configure parser for " + xml, e, null /*data*/); 410 // we'll return null below. 411 } catch (FileNotFoundException e) { 412 // this shouldn't happen since we check above. 413 } finally { 414 mBridgeInflater.setResourceReference(null); 415 } 416 } else { 417 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 418 String.format("File %s is missing!", xml), null); 419 } 420 } else { 421 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 422 String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "", 423 resource.getName()), null); 424 } 425 426 return Pair.of(null, false); 427 } 428 429 @SuppressWarnings("deprecation") 430 private ILayoutPullParser getParser(ResourceReference resource) { 431 ILayoutPullParser parser; 432 if (resource instanceof ResourceValue) { 433 parser = mProjectCallback.getParser((ResourceValue) resource); 434 } else { 435 parser = mProjectCallback.getParser(resource.getName()); 436 } 437 return parser; 438 } 439 440 // ------------ Context methods 441 442 @Override 443 public Resources getResources() { 444 return mSystemResources; 445 } 446 447 @Override 448 public Theme getTheme() { 449 return mTheme; 450 } 451 452 @Override 453 public ClassLoader getClassLoader() { 454 return this.getClass().getClassLoader(); 455 } 456 457 @Override 458 public Object getSystemService(String service) { 459 if (LAYOUT_INFLATER_SERVICE.equals(service)) { 460 return mBridgeInflater; 461 } 462 463 if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) { 464 // we need to return a valid service to avoid NPE 465 return TextServicesManager.getInstance(); 466 } 467 468 if (WINDOW_SERVICE.equals(service)) { 469 return mWindowManager; 470 } 471 472 // needed by SearchView 473 if (INPUT_METHOD_SERVICE.equals(service)) { 474 return null; 475 } 476 477 if (POWER_SERVICE.equals(service)) { 478 return new PowerManager(this, new BridgePowerManager(), new Handler()); 479 } 480 481 if (DISPLAY_SERVICE.equals(service)) { 482 return mDisplayManager; 483 } 484 485 if (ACCESSIBILITY_SERVICE.equals(service)) { 486 return AccessibilityManager.getInstance(this); 487 } 488 489 throw new UnsupportedOperationException("Unsupported Service: " + service); 490 } 491 492 493 @Override 494 public final BridgeTypedArray obtainStyledAttributes(int[] attrs) { 495 // No style is specified here, so create the typed array based on the default theme 496 // and the styles already applied to it. A null value of style indicates that the default 497 // theme should be used. 498 return createStyleBasedTypedArray(null, attrs); 499 } 500 501 @Override 502 public final BridgeTypedArray obtainStyledAttributes(int resid, int[] attrs) 503 throws Resources.NotFoundException { 504 StyleResourceValue style = null; 505 // get the StyleResourceValue based on the resId; 506 if (resid != 0) { 507 style = getStyleByDynamicId(resid); 508 509 if (style == null) { 510 // In some cases, style may not be a dynamic id, so we do a full search. 511 ResourceReference ref = resolveId(resid); 512 if (ref != null) { 513 style = mRenderResources.getStyle(ref.getName(), ref.isFramework()); 514 } 515 } 516 517 if (style == null) { 518 throw new Resources.NotFoundException(); 519 } 520 } 521 522 if (mTypedArrayCache == null) { 523 mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>(); 524 525 Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>(); 526 mTypedArrayCache.put(attrs, map); 527 528 BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs); 529 map.put(resid, ta); 530 531 return ta; 532 } 533 534 // get the 2nd map 535 Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs); 536 if (map == null) { 537 map = new HashMap<Integer, BridgeTypedArray>(); 538 mTypedArrayCache.put(attrs, map); 539 } 540 541 // get the array from the 2nd map 542 BridgeTypedArray ta = map.get(resid); 543 544 if (ta == null) { 545 ta = createStyleBasedTypedArray(style, attrs); 546 map.put(resid, ta); 547 } 548 549 return ta; 550 } 551 552 @Override 553 public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { 554 return obtainStyledAttributes(set, attrs, 0, 0); 555 } 556 557 @Override 558 public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, 559 int defStyleAttr, int defStyleRes) { 560 561 Map<String, String> defaultPropMap = null; 562 boolean isPlatformFile = true; 563 564 // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java 565 if (set instanceof BridgeXmlBlockParser) { 566 BridgeXmlBlockParser parser = null; 567 parser = (BridgeXmlBlockParser)set; 568 569 isPlatformFile = parser.isPlatformFile(); 570 571 Object key = parser.getViewCookie(); 572 if (key != null) { 573 defaultPropMap = mDefaultPropMaps.get(key); 574 if (defaultPropMap == null) { 575 defaultPropMap = new HashMap<String, String>(); 576 mDefaultPropMaps.put(key, defaultPropMap); 577 } 578 } 579 580 } else if (set instanceof BridgeLayoutParamsMapAttributes) { 581 // this is only for temp layout params generated dynamically, so this is never 582 // platform content. 583 isPlatformFile = false; 584 } else if (set != null) { // null parser is ok 585 // really this should not be happening since its instantiated in Bridge 586 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 587 "Parser is not a BridgeXmlBlockParser!", null /*data*/); 588 return null; 589 } 590 591 List<Pair<String, Boolean>> attributeList = searchAttrs(attrs); 592 593 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 594 isPlatformFile); 595 596 // look for a custom style. 597 String customStyle = null; 598 if (set != null) { 599 customStyle = set.getAttributeValue(null /* namespace*/, "style"); 600 } 601 602 StyleResourceValue customStyleValues = null; 603 if (customStyle != null) { 604 ResourceValue item = mRenderResources.findResValue(customStyle, 605 isPlatformFile /*forceFrameworkOnly*/); 606 607 // resolve it in case it links to something else 608 item = mRenderResources.resolveResValue(item); 609 610 if (item instanceof StyleResourceValue) { 611 customStyleValues = (StyleResourceValue)item; 612 } 613 } 614 615 // resolve the defStyleAttr value into a IStyleResourceValue 616 StyleResourceValue defStyleValues = null; 617 618 if (defStyleAttr != 0) { 619 // get the name from the int. 620 Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr); 621 622 if (defaultPropMap != null) { 623 String defStyleName = defStyleAttribute.getFirst(); 624 if (defStyleAttribute.getSecond()) { 625 defStyleName = "android:" + defStyleName; 626 } 627 defaultPropMap.put("style", defStyleName); 628 } 629 630 // look for the style in the current theme, and its parent: 631 ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(), 632 defStyleAttribute.getSecond()); 633 634 if (item != null) { 635 // item is a reference to a style entry. Search for it. 636 item = mRenderResources.findResValue(item.getValue(), item.isFramework()); 637 638 if (item instanceof StyleResourceValue) { 639 defStyleValues = (StyleResourceValue)item; 640 } 641 } else { 642 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR, 643 String.format( 644 "Failed to find style '%s' in current theme", 645 defStyleAttribute.getFirst()), 646 null /*data*/); 647 } 648 } else if (defStyleRes != 0) { 649 boolean isFrameworkRes = true; 650 Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); 651 if (value == null) { 652 value = mProjectCallback.resolveResourceId(defStyleRes); 653 isFrameworkRes = false; 654 } 655 656 if (value != null) { 657 if ((value.getFirst() == ResourceType.STYLE)) { 658 // look for the style in all resources: 659 StyleResourceValue item = mRenderResources.getStyle(value.getSecond(), 660 isFrameworkRes); 661 if (item != null) { 662 if (defaultPropMap != null) { 663 defaultPropMap.put("style", item.getName()); 664 } 665 666 defStyleValues = item; 667 } else { 668 Bridge.getLog().error(null, 669 String.format( 670 "Style with id 0x%x (resolved to '%s') does not exist.", 671 defStyleRes, value.getSecond()), 672 null); 673 } 674 } else { 675 Bridge.getLog().error(null, 676 String.format( 677 "Resource id 0x%x is not of type STYLE (instead %s)", 678 defStyleRes, value.getFirst().toString()), 679 null); 680 } 681 } else { 682 Bridge.getLog().error(null, 683 String.format( 684 "Failed to find style with id 0x%x in current theme", 685 defStyleRes), 686 null); 687 } 688 } 689 690 String appNamespace = mProjectCallback.getNamespace(); 691 692 if (attributeList != null) { 693 for (int index = 0 ; index < attributeList.size() ; index++) { 694 Pair<String, Boolean> attribute = attributeList.get(index); 695 696 if (attribute == null) { 697 continue; 698 } 699 700 String attrName = attribute.getFirst(); 701 boolean frameworkAttr = attribute.getSecond(); 702 String value = null; 703 if (set != null) { 704 value = set.getAttributeValue( 705 frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace, 706 attrName); 707 708 // if this is an app attribute, and the first get fails, try with the 709 // new res-auto namespace as well 710 if (!frameworkAttr && value == null) { 711 value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName); 712 } 713 } 714 715 // if there's no direct value for this attribute in the XML, we look for default 716 // values in the widget defStyle, and then in the theme. 717 if (value == null) { 718 ResourceValue resValue = null; 719 720 // look for the value in the custom style first (and its parent if needed) 721 if (customStyleValues != null) { 722 resValue = mRenderResources.findItemInStyle(customStyleValues, 723 attrName, frameworkAttr); 724 } 725 726 // then look for the value in the default Style (and its parent if needed) 727 if (resValue == null && defStyleValues != null) { 728 resValue = mRenderResources.findItemInStyle(defStyleValues, 729 attrName, frameworkAttr); 730 } 731 732 // if the item is not present in the defStyle, we look in the main theme (and 733 // its parent themes) 734 if (resValue == null) { 735 resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr); 736 } 737 738 // if we found a value, we make sure this doesn't reference another value. 739 // So we resolve it. 740 if (resValue != null) { 741 // put the first default value, before the resolution. 742 if (defaultPropMap != null) { 743 defaultPropMap.put(attrName, resValue.getValue()); 744 } 745 746 resValue = mRenderResources.resolveResValue(resValue); 747 } 748 749 ta.bridgeSetValue(index, attrName, frameworkAttr, resValue); 750 } else { 751 // there is a value in the XML, but we need to resolve it in case it's 752 // referencing another resource or a theme value. 753 ta.bridgeSetValue(index, attrName, frameworkAttr, 754 mRenderResources.resolveValue(null, attrName, value, isPlatformFile)); 755 } 756 } 757 } 758 759 ta.sealArray(); 760 761 return ta; 762 } 763 764 @Override 765 public Looper getMainLooper() { 766 return Looper.myLooper(); 767 } 768 769 770 // ------------- private new methods 771 772 /** 773 * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the 774 * values found in the given style. If no style is specified, the default theme, along with the 775 * styles applied to it are used. 776 * 777 * @see #obtainStyledAttributes(int, int[]) 778 */ 779 private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style, 780 int[] attrs) throws Resources.NotFoundException { 781 782 List<Pair<String, Boolean>> attributes = searchAttrs(attrs); 783 784 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 785 false); 786 787 // for each attribute, get its name so that we can search it in the style 788 for (int i = 0 ; i < attrs.length ; i++) { 789 Pair<String, Boolean> attribute = attributes.get(i); 790 791 if (attribute != null) { 792 // look for the value in the given style 793 ResourceValue resValue; 794 if (style != null) { 795 resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(), 796 attribute.getSecond()); 797 } else { 798 resValue = mRenderResources.findItemInTheme(attribute.getFirst(), 799 attribute.getSecond()); 800 } 801 802 if (resValue != null) { 803 // resolve it to make sure there are no references left. 804 ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(), 805 mRenderResources.resolveResValue(resValue)); 806 } 807 } 808 } 809 810 ta.sealArray(); 811 812 return ta; 813 } 814 815 /** 816 * The input int[] attrs is a list of attributes. The returns a list of information about 817 * each attributes. The information is (name, isFramework) 818 * <p/> 819 * 820 * @param attrs An attribute array reference given to obtainStyledAttributes. 821 * @return List of attribute information. 822 */ 823 private List<Pair<String, Boolean>> searchAttrs(int[] attrs) { 824 List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length); 825 826 // for each attribute, get its name so that we can search it in the style 827 for (int attr : attrs) { 828 Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr); 829 boolean isFramework = false; 830 if (resolvedResource != null) { 831 isFramework = true; 832 } else { 833 resolvedResource = mProjectCallback.resolveResourceId(attr); 834 } 835 836 if (resolvedResource != null) { 837 results.add(Pair.of(resolvedResource.getSecond(), isFramework)); 838 } else { 839 results.add(null); 840 } 841 } 842 843 return results; 844 } 845 846 /** 847 * Searches for the attribute referenced by its internal id. 848 * 849 * @param attr An attribute reference given to obtainStyledAttributes such as defStyle. 850 * @return A (name, isFramework) pair describing the attribute if found. Returns null 851 * if nothing is found. 852 */ 853 public Pair<String, Boolean> searchAttr(int attr) { 854 Pair<ResourceType, String> info = Bridge.resolveResourceId(attr); 855 if (info != null) { 856 return Pair.of(info.getSecond(), Boolean.TRUE); 857 } 858 859 info = mProjectCallback.resolveResourceId(attr); 860 if (info != null) { 861 return Pair.of(info.getSecond(), Boolean.FALSE); 862 } 863 864 return null; 865 } 866 867 public int getDynamicIdByStyle(StyleResourceValue resValue) { 868 if (mDynamicIdToStyleMap == null) { 869 // create the maps. 870 mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>(); 871 mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>(); 872 } 873 874 // look for an existing id 875 Integer id = mStyleToDynamicIdMap.get(resValue); 876 877 if (id == null) { 878 // generate a new id 879 id = ++mDynamicIdGenerator; 880 881 // and add it to the maps. 882 mDynamicIdToStyleMap.put(id, resValue); 883 mStyleToDynamicIdMap.put(resValue, id); 884 } 885 886 return id; 887 } 888 889 private StyleResourceValue getStyleByDynamicId(int i) { 890 if (mDynamicIdToStyleMap != null) { 891 return mDynamicIdToStyleMap.get(i); 892 } 893 894 return null; 895 } 896 897 public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) { 898 if (getRenderResources().getFrameworkResource(resType, resName) != null) { 899 // Bridge.getResourceId creates a new resource id if an existing one isn't found. So, 900 // we check for the existence of the resource before calling it. 901 return Bridge.getResourceId(resType, resName); 902 } 903 904 return defValue; 905 } 906 907 public int getProjectResourceValue(ResourceType resType, String resName, int defValue) { 908 // getResourceId creates a new resource id if an existing resource id isn't found. So, we 909 // check for the existence of the resource before calling it. 910 if (getRenderResources().getProjectResource(resType, resName) != null) { 911 if (mProjectCallback != null) { 912 Integer value = mProjectCallback.getResourceId(resType, resName); 913 if (value != null) { 914 return value; 915 } 916 } 917 } 918 919 return defValue; 920 } 921 922 //------------ NOT OVERRIDEN -------------------- 923 924 @Override 925 public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) { 926 // pass 927 return false; 928 } 929 930 @Override 931 public int checkCallingOrSelfPermission(String arg0) { 932 // pass 933 return 0; 934 } 935 936 @Override 937 public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) { 938 // pass 939 return 0; 940 } 941 942 @Override 943 public int checkCallingPermission(String arg0) { 944 // pass 945 return 0; 946 } 947 948 @Override 949 public int checkCallingUriPermission(Uri arg0, int arg1) { 950 // pass 951 return 0; 952 } 953 954 @Override 955 public int checkPermission(String arg0, int arg1, int arg2) { 956 // pass 957 return 0; 958 } 959 960 @Override 961 public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) { 962 // pass 963 return 0; 964 } 965 966 @Override 967 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) { 968 // pass 969 return 0; 970 } 971 972 @Override 973 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) { 974 // pass 975 return 0; 976 } 977 978 @Override 979 public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3, 980 int arg4, int arg5) { 981 // pass 982 return 0; 983 } 984 985 @Override 986 public void clearWallpaper() { 987 // pass 988 989 } 990 991 @Override 992 public Context createPackageContext(String arg0, int arg1) { 993 // pass 994 return null; 995 } 996 997 @Override 998 public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) { 999 // pass 1000 return null; 1001 } 1002 1003 @Override 1004 public Context createConfigurationContext(Configuration overrideConfiguration) { 1005 // pass 1006 return null; 1007 } 1008 1009 @Override 1010 public Context createDisplayContext(Display display) { 1011 // pass 1012 return null; 1013 } 1014 1015 @Override 1016 public String[] databaseList() { 1017 // pass 1018 return null; 1019 } 1020 1021 @Override 1022 public Context createApplicationContext(ApplicationInfo application, int flags) 1023 throws PackageManager.NameNotFoundException { 1024 return null; 1025 } 1026 1027 @Override 1028 public boolean deleteDatabase(String arg0) { 1029 // pass 1030 return false; 1031 } 1032 1033 @Override 1034 public boolean deleteFile(String arg0) { 1035 // pass 1036 return false; 1037 } 1038 1039 @Override 1040 public void enforceCallingOrSelfPermission(String arg0, String arg1) { 1041 // pass 1042 1043 } 1044 1045 @Override 1046 public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1, 1047 String arg2) { 1048 // pass 1049 1050 } 1051 1052 @Override 1053 public void enforceCallingPermission(String arg0, String arg1) { 1054 // pass 1055 1056 } 1057 1058 @Override 1059 public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) { 1060 // pass 1061 1062 } 1063 1064 @Override 1065 public void enforcePermission(String arg0, int arg1, int arg2, String arg3) { 1066 // pass 1067 1068 } 1069 1070 @Override 1071 public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3, 1072 String arg4) { 1073 // pass 1074 1075 } 1076 1077 @Override 1078 public void enforceUriPermission(Uri arg0, String arg1, String arg2, 1079 int arg3, int arg4, int arg5, String arg6) { 1080 // pass 1081 1082 } 1083 1084 @Override 1085 public String[] fileList() { 1086 // pass 1087 return null; 1088 } 1089 1090 @Override 1091 public AssetManager getAssets() { 1092 // pass 1093 return null; 1094 } 1095 1096 @Override 1097 public File getCacheDir() { 1098 // pass 1099 return null; 1100 } 1101 1102 @Override 1103 public File getCodeCacheDir() { 1104 // pass 1105 return null; 1106 } 1107 1108 @Override 1109 public File getExternalCacheDir() { 1110 // pass 1111 return null; 1112 } 1113 1114 @Override 1115 public ContentResolver getContentResolver() { 1116 if (mContentResolver == null) { 1117 mContentResolver = new BridgeContentResolver(this); 1118 } 1119 return mContentResolver; 1120 } 1121 1122 @Override 1123 public File getDatabasePath(String arg0) { 1124 // pass 1125 return null; 1126 } 1127 1128 @Override 1129 public File getDir(String arg0, int arg1) { 1130 // pass 1131 return null; 1132 } 1133 1134 @Override 1135 public File getFileStreamPath(String arg0) { 1136 // pass 1137 return null; 1138 } 1139 1140 @Override 1141 public File getFilesDir() { 1142 // pass 1143 return null; 1144 } 1145 1146 @Override 1147 public File getNoBackupFilesDir() { 1148 // pass 1149 return null; 1150 } 1151 1152 @Override 1153 public File getExternalFilesDir(String type) { 1154 // pass 1155 return null; 1156 } 1157 1158 @Override 1159 public String getPackageCodePath() { 1160 // pass 1161 return null; 1162 } 1163 1164 @Override 1165 public PackageManager getPackageManager() { 1166 // pass 1167 return null; 1168 } 1169 1170 @Override 1171 public String getPackageName() { 1172 // pass 1173 return null; 1174 } 1175 1176 @Override 1177 public String getBasePackageName() { 1178 // pass 1179 return null; 1180 } 1181 1182 @Override 1183 public String getOpPackageName() { 1184 // pass 1185 return null; 1186 } 1187 1188 @Override 1189 public ApplicationInfo getApplicationInfo() { 1190 return mApplicationInfo; 1191 } 1192 1193 @Override 1194 public String getPackageResourcePath() { 1195 // pass 1196 return null; 1197 } 1198 1199 @Override 1200 public File getSharedPrefsFile(String name) { 1201 // pass 1202 return null; 1203 } 1204 1205 @Override 1206 public SharedPreferences getSharedPreferences(String arg0, int arg1) { 1207 if (mSharedPreferences == null) { 1208 mSharedPreferences = new BridgeSharedPreferences(); 1209 } 1210 return mSharedPreferences; 1211 } 1212 1213 @Override 1214 public Drawable getWallpaper() { 1215 // pass 1216 return null; 1217 } 1218 1219 @Override 1220 public int getWallpaperDesiredMinimumWidth() { 1221 return -1; 1222 } 1223 1224 @Override 1225 public int getWallpaperDesiredMinimumHeight() { 1226 return -1; 1227 } 1228 1229 @Override 1230 public void grantUriPermission(String arg0, Uri arg1, int arg2) { 1231 // pass 1232 1233 } 1234 1235 @Override 1236 public FileInputStream openFileInput(String arg0) throws FileNotFoundException { 1237 // pass 1238 return null; 1239 } 1240 1241 @Override 1242 public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException { 1243 // pass 1244 return null; 1245 } 1246 1247 @Override 1248 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) { 1249 // pass 1250 return null; 1251 } 1252 1253 @Override 1254 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, 1255 CursorFactory arg2, DatabaseErrorHandler arg3) { 1256 // pass 1257 return null; 1258 } 1259 1260 @Override 1261 public Drawable peekWallpaper() { 1262 // pass 1263 return null; 1264 } 1265 1266 @Override 1267 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) { 1268 // pass 1269 return null; 1270 } 1271 1272 @Override 1273 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, 1274 String arg2, Handler arg3) { 1275 // pass 1276 return null; 1277 } 1278 1279 @Override 1280 public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5, 1281 IntentFilter arg1, String arg2, Handler arg3) { 1282 // pass 1283 return null; 1284 } 1285 1286 @Override 1287 public void removeStickyBroadcast(Intent arg0) { 1288 // pass 1289 1290 } 1291 1292 @Override 1293 public void revokeUriPermission(Uri arg0, int arg1) { 1294 // pass 1295 1296 } 1297 1298 @Override 1299 public void sendBroadcast(Intent arg0) { 1300 // pass 1301 1302 } 1303 1304 @Override 1305 public void sendBroadcast(Intent arg0, String arg1) { 1306 // pass 1307 1308 } 1309 1310 @Override 1311 public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { 1312 // pass 1313 } 1314 1315 @Override 1316 public void sendOrderedBroadcast(Intent arg0, String arg1) { 1317 // pass 1318 1319 } 1320 1321 @Override 1322 public void sendOrderedBroadcast(Intent arg0, String arg1, 1323 BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, 1324 Bundle arg6) { 1325 // pass 1326 1327 } 1328 1329 @Override 1330 public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, 1331 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, 1332 String initialData, Bundle initialExtras) { 1333 // pass 1334 } 1335 1336 @Override 1337 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 1338 // pass 1339 } 1340 1341 @Override 1342 public void sendBroadcastAsUser(Intent intent, UserHandle user, 1343 String receiverPermission) { 1344 // pass 1345 } 1346 1347 @Override 1348 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1349 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 1350 int initialCode, String initialData, Bundle initialExtras) { 1351 // pass 1352 } 1353 1354 @Override 1355 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1356 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 1357 Handler scheduler, 1358 int initialCode, String initialData, Bundle initialExtras) { 1359 // pass 1360 } 1361 1362 @Override 1363 public void sendStickyBroadcast(Intent arg0) { 1364 // pass 1365 1366 } 1367 1368 @Override 1369 public void sendStickyOrderedBroadcast(Intent intent, 1370 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, 1371 Bundle initialExtras) { 1372 // pass 1373 } 1374 1375 @Override 1376 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { 1377 // pass 1378 } 1379 1380 @Override 1381 public void sendStickyOrderedBroadcastAsUser(Intent intent, 1382 UserHandle user, BroadcastReceiver resultReceiver, 1383 Handler scheduler, int initialCode, String initialData, 1384 Bundle initialExtras) { 1385 // pass 1386 } 1387 1388 @Override 1389 public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { 1390 // pass 1391 } 1392 1393 @Override 1394 public void setTheme(int arg0) { 1395 // pass 1396 1397 } 1398 1399 @Override 1400 public void setWallpaper(Bitmap arg0) throws IOException { 1401 // pass 1402 1403 } 1404 1405 @Override 1406 public void setWallpaper(InputStream arg0) throws IOException { 1407 // pass 1408 1409 } 1410 1411 @Override 1412 public void startActivity(Intent arg0) { 1413 // pass 1414 } 1415 1416 @Override 1417 public void startActivity(Intent arg0, Bundle arg1) { 1418 // pass 1419 } 1420 1421 @Override 1422 public void startIntentSender(IntentSender intent, 1423 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) 1424 throws IntentSender.SendIntentException { 1425 // pass 1426 } 1427 1428 @Override 1429 public void startIntentSender(IntentSender intent, 1430 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, 1431 Bundle options) throws IntentSender.SendIntentException { 1432 // pass 1433 } 1434 1435 @Override 1436 public boolean startInstrumentation(ComponentName arg0, String arg1, 1437 Bundle arg2) { 1438 // pass 1439 return false; 1440 } 1441 1442 @Override 1443 public ComponentName startService(Intent arg0) { 1444 // pass 1445 return null; 1446 } 1447 1448 @Override 1449 public boolean stopService(Intent arg0) { 1450 // pass 1451 return false; 1452 } 1453 1454 @Override 1455 public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) { 1456 // pass 1457 return null; 1458 } 1459 1460 @Override 1461 public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) { 1462 // pass 1463 return false; 1464 } 1465 1466 @Override 1467 public void unbindService(ServiceConnection arg0) { 1468 // pass 1469 1470 } 1471 1472 @Override 1473 public void unregisterReceiver(BroadcastReceiver arg0) { 1474 // pass 1475 1476 } 1477 1478 @Override 1479 public Context getApplicationContext() { 1480 return this; 1481 } 1482 1483 @Override 1484 public void startActivities(Intent[] arg0) { 1485 // pass 1486 1487 } 1488 1489 @Override 1490 public void startActivities(Intent[] arg0, Bundle arg1) { 1491 // pass 1492 1493 } 1494 1495 @Override 1496 public boolean isRestricted() { 1497 return false; 1498 } 1499 1500 @Override 1501 public File getObbDir() { 1502 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null); 1503 return null; 1504 } 1505 1506 @Override 1507 public DisplayAdjustments getDisplayAdjustments(int displayId) { 1508 // pass 1509 return null; 1510 } 1511 1512 @Override 1513 public int getUserId() { 1514 return 0; // not used 1515 } 1516 1517 @Override 1518 public File[] getExternalFilesDirs(String type) { 1519 // pass 1520 return new File[0]; 1521 } 1522 1523 @Override 1524 public File[] getObbDirs() { 1525 // pass 1526 return new File[0]; 1527 } 1528 1529 @Override 1530 public File[] getExternalCacheDirs() { 1531 // pass 1532 return new File[0]; 1533 } 1534 1535 @Override 1536 public File[] getExternalMediaDirs() { 1537 // pass 1538 return new File[0]; 1539 } 1540} 1541