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