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