BridgeContext.java revision 040f7446638281d80a7c6ca2b25f73b59dcef421
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 142 /** 143 * @param projectKey An Object identifying the project. This is used for the cache mechanism. 144 * @param metrics the {@link DisplayMetrics}. 145 * @param renderResources the configured resources (both framework and projects) for this 146 * render. 147 * @param config the Configuration object for this render. 148 * @param targetSdkVersion the targetSdkVersion of the application. 149 */ 150 public BridgeContext(Object projectKey, DisplayMetrics metrics, 151 RenderResources renderResources, 152 AssetRepository assets, 153 LayoutlibCallback layoutlibCallback, 154 Configuration config, 155 int targetSdkVersion, 156 boolean hasRtlSupport) { 157 mProjectKey = projectKey; 158 mMetrics = metrics; 159 mLayoutlibCallback = layoutlibCallback; 160 161 mRenderResources = renderResources; 162 mConfig = config; 163 mAssets = new BridgeAssetManager(); 164 mAssets.setAssetRepository(assets); 165 166 mApplicationInfo = new ApplicationInfo(); 167 mApplicationInfo.targetSdkVersion = targetSdkVersion; 168 if (hasRtlSupport) { 169 mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL; 170 } 171 172 mWindowManager = new WindowManagerImpl(mMetrics); 173 mDisplayManager = new DisplayManager(this); 174 } 175 176 /** 177 * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its 178 * {@link DisplayMetrics}, {@link Configuration}, and {@link LayoutlibCallback}. 179 * 180 * @see #disposeResources() 181 */ 182 public void initResources() { 183 AssetManager assetManager = AssetManager.getSystem(); 184 185 mSystemResources = BridgeResources.initSystem( 186 this, 187 assetManager, 188 mMetrics, 189 mConfig, 190 mLayoutlibCallback); 191 mTheme = mSystemResources.newTheme(); 192 } 193 194 /** 195 * Disposes the {@link Resources} singleton. 196 */ 197 public void disposeResources() { 198 BridgeResources.disposeSystem(); 199 } 200 201 public void setBridgeInflater(BridgeInflater inflater) { 202 mBridgeInflater = inflater; 203 } 204 205 public void addViewKey(View view, Object viewKey) { 206 mViewKeyMap.put(view, viewKey); 207 } 208 209 public Object getViewKey(View view) { 210 return mViewKeyMap.get(view); 211 } 212 213 public void addCookie(Object o, Object cookie) { 214 mViewKeyHelpMap.put(o, cookie); 215 } 216 217 public Object getCookie(Object o) { 218 return mViewKeyHelpMap.get(o); 219 } 220 221 public Object getProjectKey() { 222 return mProjectKey; 223 } 224 225 public DisplayMetrics getMetrics() { 226 return mMetrics; 227 } 228 229 public LayoutlibCallback getLayoutlibCallback() { 230 return mLayoutlibCallback; 231 } 232 233 public RenderResources getRenderResources() { 234 return mRenderResources; 235 } 236 237 public Map<String, String> getDefaultPropMap(Object key) { 238 return mDefaultPropMaps.get(key); 239 } 240 241 public Configuration getConfiguration() { 242 return mConfig; 243 } 244 245 /** 246 * Adds a parser to the stack. 247 * @param parser the parser to add. 248 */ 249 public void pushParser(BridgeXmlBlockParser parser) { 250 if (ParserFactory.LOG_PARSER) { 251 System.out.println("PUSH " + parser.getParser().toString()); 252 } 253 mParserStack.push(parser); 254 } 255 256 /** 257 * Removes the parser at the top of the stack 258 */ 259 public void popParser() { 260 BridgeXmlBlockParser parser = mParserStack.pop(); 261 if (ParserFactory.LOG_PARSER) { 262 System.out.println("POPD " + parser.getParser().toString()); 263 } 264 } 265 266 /** 267 * Returns the current parser at the top the of the stack. 268 * @return a parser or null. 269 */ 270 public BridgeXmlBlockParser getCurrentParser() { 271 return mParserStack.peek(); 272 } 273 274 /** 275 * Returns the previous parser. 276 * @return a parser or null if there isn't any previous parser 277 */ 278 public BridgeXmlBlockParser getPreviousParser() { 279 if (mParserStack.size() < 2) { 280 return null; 281 } 282 return mParserStack.get(mParserStack.size() - 2); 283 } 284 285 public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 286 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid); 287 boolean isFrameworkRes = true; 288 if (resourceInfo == null) { 289 resourceInfo = mLayoutlibCallback.resolveResourceId(resid); 290 isFrameworkRes = false; 291 } 292 293 if (resourceInfo == null) { 294 return false; 295 } 296 297 ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(), 298 isFrameworkRes); 299 if (resolveRefs) { 300 value = mRenderResources.resolveResValue(value); 301 } 302 303 if (value == null) { 304 // unable to find the attribute. 305 return false; 306 } 307 308 // check if this is a style resource 309 if (value instanceof StyleResourceValue) { 310 // get the id that will represent this style. 311 outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value); 312 return true; 313 } 314 315 int a; 316 // if this is a framework value. 317 if (value.isFramework()) { 318 // look for idName in the android R classes. 319 // use 0 a default res value as it's not a valid id value. 320 a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 321 } else { 322 // look for idName in the project R class. 323 // use 0 a default res value as it's not a valid id value. 324 a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/); 325 } 326 327 if (a != 0) { 328 outValue.resourceId = a; 329 return true; 330 } 331 332 return false; 333 } 334 335 336 public ResourceReference resolveId(int id) { 337 // first get the String related to this id in the framework 338 Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id); 339 340 if (resourceInfo != null) { 341 return new ResourceReference(resourceInfo.getSecond(), true); 342 } 343 344 // didn't find a match in the framework? look in the project. 345 if (mLayoutlibCallback != null) { 346 resourceInfo = mLayoutlibCallback.resolveResourceId(id); 347 348 if (resourceInfo != null) { 349 return new ResourceReference(resourceInfo.getSecond(), false); 350 } 351 } 352 353 // The base value for R.style is 0x01030000 and the custom style is 0x02030000. 354 // So, if the second byte is 03, it's probably a style. 355 if ((id >> 16 & 0xFF) == 0x03) { 356 return getStyleByDynamicId(id); 357 } 358 return null; 359 } 360 361 public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent, 362 boolean attachToRoot, boolean skipCallbackParser) { 363 boolean isPlatformLayout = resource.isFramework(); 364 365 if (!isPlatformLayout && !skipCallbackParser) { 366 // check if the project callback can provide us with a custom parser. 367 ILayoutPullParser parser = getParser(resource); 368 369 if (parser != null) { 370 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 371 this, resource.isFramework()); 372 try { 373 pushParser(blockParser); 374 return Pair.of( 375 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 376 true); 377 } finally { 378 popParser(); 379 } 380 } 381 } 382 383 ResourceValue resValue; 384 if (resource instanceof ResourceValue) { 385 resValue = (ResourceValue) resource; 386 } else { 387 if (isPlatformLayout) { 388 resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT, 389 resource.getName()); 390 } else { 391 resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT, 392 resource.getName()); 393 } 394 } 395 396 if (resValue != null) { 397 398 File xml = new File(resValue.getValue()); 399 if (xml.isFile()) { 400 // we need to create a pull parser around the layout XML file, and then 401 // give that to our XmlBlockParser 402 try { 403 XmlPullParser parser = ParserFactory.create(xml); 404 405 // set the resource ref to have correct view cookies 406 mBridgeInflater.setResourceReference(resource); 407 408 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, 409 this, resource.isFramework()); 410 try { 411 pushParser(blockParser); 412 return Pair.of( 413 mBridgeInflater.inflate(blockParser, parent, attachToRoot), 414 false); 415 } finally { 416 popParser(); 417 } 418 } catch (XmlPullParserException e) { 419 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 420 "Failed to configure parser for " + xml, e, null /*data*/); 421 // we'll return null below. 422 } catch (FileNotFoundException e) { 423 // this shouldn't happen since we check above. 424 } finally { 425 mBridgeInflater.setResourceReference(null); 426 } 427 } else { 428 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 429 String.format("File %s is missing!", xml), null); 430 } 431 } else { 432 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 433 String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "", 434 resource.getName()), null); 435 } 436 437 return Pair.of(null, false); 438 } 439 440 @SuppressWarnings("deprecation") 441 private ILayoutPullParser getParser(ResourceReference resource) { 442 ILayoutPullParser parser; 443 if (resource instanceof ResourceValue) { 444 parser = mLayoutlibCallback.getParser((ResourceValue) resource); 445 } else { 446 parser = mLayoutlibCallback.getParser(resource.getName()); 447 } 448 return parser; 449 } 450 451 // ------------ Context methods 452 453 @Override 454 public Resources getResources() { 455 return mSystemResources; 456 } 457 458 @Override 459 public Theme getTheme() { 460 return mTheme; 461 } 462 463 @Override 464 public ClassLoader getClassLoader() { 465 return this.getClass().getClassLoader(); 466 } 467 468 @Override 469 public Object getSystemService(String service) { 470 if (LAYOUT_INFLATER_SERVICE.equals(service)) { 471 return mBridgeInflater; 472 } 473 474 if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) { 475 // we need to return a valid service to avoid NPE 476 return TextServicesManager.getInstance(); 477 } 478 479 if (WINDOW_SERVICE.equals(service)) { 480 return mWindowManager; 481 } 482 483 // needed by SearchView 484 if (INPUT_METHOD_SERVICE.equals(service)) { 485 return null; 486 } 487 488 if (POWER_SERVICE.equals(service)) { 489 return new PowerManager(this, new BridgePowerManager(), new Handler()); 490 } 491 492 if (DISPLAY_SERVICE.equals(service)) { 493 return mDisplayManager; 494 } 495 496 if (ACCESSIBILITY_SERVICE.equals(service)) { 497 return AccessibilityManager.getInstance(this); 498 } 499 500 throw new UnsupportedOperationException("Unsupported Service: " + service); 501 } 502 503 @Override 504 public String getSystemServiceName(Class<?> serviceClass) { 505 if (serviceClass.equals(LayoutInflater.class)) { 506 return LAYOUT_INFLATER_SERVICE; 507 } 508 509 if (serviceClass.equals(TextServicesManager.class)) { 510 return TEXT_SERVICES_MANAGER_SERVICE; 511 } 512 513 if (serviceClass.equals(WindowManager.class)) { 514 return WINDOW_SERVICE; 515 } 516 517 if (serviceClass.equals(PowerManager.class)) { 518 return POWER_SERVICE; 519 } 520 521 if (serviceClass.equals(DisplayManager.class)) { 522 return DISPLAY_SERVICE; 523 } 524 525 if (serviceClass.equals(AccessibilityManager.class)) { 526 return ACCESSIBILITY_SERVICE; 527 } 528 529 throw new UnsupportedOperationException("Unsupported Service: " + serviceClass); 530 } 531 532 @Override 533 public final BridgeTypedArray obtainStyledAttributes(int[] attrs) { 534 // No style is specified here, so create the typed array based on the default theme 535 // and the styles already applied to it. A null value of style indicates that the default 536 // theme should be used. 537 return createStyleBasedTypedArray(null, attrs); 538 } 539 540 @Override 541 public final BridgeTypedArray obtainStyledAttributes(int resid, int[] attrs) 542 throws Resources.NotFoundException { 543 StyleResourceValue style = null; 544 // get the StyleResourceValue based on the resId; 545 if (resid != 0) { 546 style = getStyleByDynamicId(resid); 547 548 if (style == null) { 549 // In some cases, style may not be a dynamic id, so we do a full search. 550 ResourceReference ref = resolveId(resid); 551 if (ref != null) { 552 style = mRenderResources.getStyle(ref.getName(), ref.isFramework()); 553 } 554 } 555 556 if (style == null) { 557 throw new Resources.NotFoundException(); 558 } 559 } 560 561 if (mTypedArrayCache == null) { 562 mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>(); 563 564 Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>(); 565 mTypedArrayCache.put(attrs, map); 566 567 BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs); 568 map.put(resid, ta); 569 570 return ta; 571 } 572 573 // get the 2nd map 574 Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs); 575 if (map == null) { 576 map = new HashMap<Integer, BridgeTypedArray>(); 577 mTypedArrayCache.put(attrs, map); 578 } 579 580 // get the array from the 2nd map 581 BridgeTypedArray ta = map.get(resid); 582 583 if (ta == null) { 584 ta = createStyleBasedTypedArray(style, attrs); 585 map.put(resid, ta); 586 } 587 588 return ta; 589 } 590 591 @Override 592 public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { 593 return obtainStyledAttributes(set, attrs, 0, 0); 594 } 595 596 @Override 597 public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, 598 int defStyleAttr, int defStyleRes) { 599 600 Map<String, String> defaultPropMap = null; 601 boolean isPlatformFile = true; 602 603 // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java 604 if (set instanceof BridgeXmlBlockParser) { 605 BridgeXmlBlockParser parser; 606 parser = (BridgeXmlBlockParser)set; 607 608 isPlatformFile = parser.isPlatformFile(); 609 610 Object key = parser.getViewCookie(); 611 if (key != null) { 612 defaultPropMap = mDefaultPropMaps.get(key); 613 if (defaultPropMap == null) { 614 defaultPropMap = new HashMap<String, String>(); 615 mDefaultPropMaps.put(key, defaultPropMap); 616 } 617 } 618 619 } else if (set instanceof BridgeLayoutParamsMapAttributes) { 620 // this is only for temp layout params generated dynamically, so this is never 621 // platform content. 622 isPlatformFile = false; 623 } else if (set != null) { // null parser is ok 624 // really this should not be happening since its instantiated in Bridge 625 Bridge.getLog().error(LayoutLog.TAG_BROKEN, 626 "Parser is not a BridgeXmlBlockParser!", null); 627 return null; 628 } 629 630 List<Pair<String, Boolean>> attributeList = searchAttrs(attrs); 631 632 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 633 isPlatformFile); 634 635 // look for a custom style. 636 String customStyle = null; 637 if (set != null) { 638 customStyle = set.getAttributeValue(null, "style"); 639 } 640 641 StyleResourceValue customStyleValues = null; 642 if (customStyle != null) { 643 ResourceValue item = mRenderResources.findResValue(customStyle, 644 isPlatformFile /*forceFrameworkOnly*/); 645 646 // resolve it in case it links to something else 647 item = mRenderResources.resolveResValue(item); 648 649 if (item instanceof StyleResourceValue) { 650 customStyleValues = (StyleResourceValue)item; 651 } 652 } 653 654 // resolve the defStyleAttr value into a IStyleResourceValue 655 StyleResourceValue defStyleValues = null; 656 657 if (defStyleAttr != 0) { 658 // get the name from the int. 659 Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr); 660 661 if (defStyleAttribute == null) { 662 // This should be rare. Happens trying to map R.style.foo to @style/foo fails. 663 // This will happen if the user explicitly used a non existing int value for 664 // defStyleAttr or there's something wrong with the project structure/build. 665 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE, 666 "Failed to find the style corresponding to the id " + defStyleAttr, null); 667 } else { 668 if (defaultPropMap != null) { 669 String defStyleName = defStyleAttribute.getFirst(); 670 if (defStyleAttribute.getSecond()) { 671 defStyleName = "android:" + defStyleName; 672 } 673 defaultPropMap.put("style", defStyleName); 674 } 675 676 // look for the style in the current theme, and its parent: 677 ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(), 678 defStyleAttribute.getSecond()); 679 680 if (item != null) { 681 // item is a reference to a style entry. Search for it. 682 item = mRenderResources.findResValue(item.getValue(), item.isFramework()); 683 684 if (item instanceof StyleResourceValue) { 685 defStyleValues = (StyleResourceValue) item; 686 } 687 } else { 688 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR, 689 String.format( 690 "Failed to find style '%s' in current theme", 691 defStyleAttribute.getFirst()), 692 null); 693 } 694 } 695 } else if (defStyleRes != 0) { 696 boolean isFrameworkRes = true; 697 Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); 698 if (value == null) { 699 value = mLayoutlibCallback.resolveResourceId(defStyleRes); 700 isFrameworkRes = false; 701 } 702 703 if (value != null) { 704 if ((value.getFirst() == ResourceType.STYLE)) { 705 // look for the style in all resources: 706 StyleResourceValue item = mRenderResources.getStyle(value.getSecond(), 707 isFrameworkRes); 708 if (item != null) { 709 if (defaultPropMap != null) { 710 defaultPropMap.put("style", item.getName()); 711 } 712 713 defStyleValues = item; 714 } else { 715 Bridge.getLog().error(null, 716 String.format( 717 "Style with id 0x%x (resolved to '%s') does not exist.", 718 defStyleRes, value.getSecond()), 719 null); 720 } 721 } else { 722 Bridge.getLog().error(null, 723 String.format( 724 "Resource id 0x%x is not of type STYLE (instead %s)", 725 defStyleRes, value.getFirst().toString()), 726 null); 727 } 728 } else { 729 Bridge.getLog().error(null, 730 String.format( 731 "Failed to find style with id 0x%x in current theme", 732 defStyleRes), 733 null); 734 } 735 } 736 737 String appNamespace = mLayoutlibCallback.getNamespace(); 738 739 if (attributeList != null) { 740 for (int index = 0 ; index < attributeList.size() ; index++) { 741 Pair<String, Boolean> attribute = attributeList.get(index); 742 743 if (attribute == null) { 744 continue; 745 } 746 747 String attrName = attribute.getFirst(); 748 boolean frameworkAttr = attribute.getSecond(); 749 String value = null; 750 if (set != null) { 751 value = set.getAttributeValue( 752 frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace, 753 attrName); 754 755 // if this is an app attribute, and the first get fails, try with the 756 // new res-auto namespace as well 757 if (!frameworkAttr && value == null) { 758 value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName); 759 } 760 } 761 762 // if there's no direct value for this attribute in the XML, we look for default 763 // values in the widget defStyle, and then in the theme. 764 if (value == null) { 765 ResourceValue resValue = null; 766 767 // look for the value in the custom style first (and its parent if needed) 768 if (customStyleValues != null) { 769 resValue = mRenderResources.findItemInStyle(customStyleValues, 770 attrName, frameworkAttr); 771 } 772 773 // then look for the value in the default Style (and its parent if needed) 774 if (resValue == null && defStyleValues != null) { 775 resValue = mRenderResources.findItemInStyle(defStyleValues, 776 attrName, frameworkAttr); 777 } 778 779 // if the item is not present in the defStyle, we look in the main theme (and 780 // its parent themes) 781 if (resValue == null) { 782 resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr); 783 } 784 785 // if we found a value, we make sure this doesn't reference another value. 786 // So we resolve it. 787 if (resValue != null) { 788 // put the first default value, before the resolution. 789 if (defaultPropMap != null) { 790 defaultPropMap.put(attrName, resValue.getValue()); 791 } 792 793 resValue = mRenderResources.resolveResValue(resValue); 794 } 795 796 ta.bridgeSetValue(index, attrName, frameworkAttr, resValue); 797 } else { 798 // there is a value in the XML, but we need to resolve it in case it's 799 // referencing another resource or a theme value. 800 ta.bridgeSetValue(index, attrName, frameworkAttr, 801 mRenderResources.resolveValue(null, attrName, value, isPlatformFile)); 802 } 803 } 804 } 805 806 ta.sealArray(); 807 808 return ta; 809 } 810 811 @Override 812 public Looper getMainLooper() { 813 return Looper.myLooper(); 814 } 815 816 817 @Override 818 public String getPackageName() { 819 if (mApplicationInfo.packageName == null) { 820 mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE); 821 } 822 return mApplicationInfo.packageName; 823 } 824 825 // ------------- private new methods 826 827 /** 828 * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the 829 * values found in the given style. If no style is specified, the default theme, along with the 830 * styles applied to it are used. 831 * 832 * @see #obtainStyledAttributes(int, int[]) 833 */ 834 private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style, 835 int[] attrs) throws Resources.NotFoundException { 836 837 List<Pair<String, Boolean>> attributes = searchAttrs(attrs); 838 839 BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, 840 false); 841 842 // for each attribute, get its name so that we can search it in the style 843 for (int i = 0 ; i < attrs.length ; i++) { 844 Pair<String, Boolean> attribute = attributes.get(i); 845 846 if (attribute != null) { 847 // look for the value in the given style 848 ResourceValue resValue; 849 if (style != null) { 850 resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(), 851 attribute.getSecond()); 852 } else { 853 resValue = mRenderResources.findItemInTheme(attribute.getFirst(), 854 attribute.getSecond()); 855 } 856 857 if (resValue != null) { 858 // resolve it to make sure there are no references left. 859 ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(), 860 mRenderResources.resolveResValue(resValue)); 861 } 862 } 863 } 864 865 ta.sealArray(); 866 867 return ta; 868 } 869 870 /** 871 * The input int[] attrs is a list of attributes. The returns a list of information about 872 * each attributes. The information is (name, isFramework) 873 * <p/> 874 * 875 * @param attrs An attribute array reference given to obtainStyledAttributes. 876 * @return List of attribute information. 877 */ 878 private List<Pair<String, Boolean>> searchAttrs(int[] attrs) { 879 List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length); 880 881 // for each attribute, get its name so that we can search it in the style 882 for (int attr : attrs) { 883 Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr); 884 boolean isFramework = false; 885 if (resolvedResource != null) { 886 isFramework = true; 887 } else { 888 resolvedResource = mLayoutlibCallback.resolveResourceId(attr); 889 } 890 891 if (resolvedResource != null) { 892 results.add(Pair.of(resolvedResource.getSecond(), isFramework)); 893 } else { 894 results.add(null); 895 } 896 } 897 898 return results; 899 } 900 901 /** 902 * Searches for the attribute referenced by its internal id. 903 * 904 * @param attr An attribute reference given to obtainStyledAttributes such as defStyle. 905 * @return A (name, isFramework) pair describing the attribute if found. Returns null 906 * if nothing is found. 907 */ 908 public Pair<String, Boolean> searchAttr(int attr) { 909 Pair<ResourceType, String> info = Bridge.resolveResourceId(attr); 910 if (info != null) { 911 return Pair.of(info.getSecond(), Boolean.TRUE); 912 } 913 914 info = mLayoutlibCallback.resolveResourceId(attr); 915 if (info != null) { 916 return Pair.of(info.getSecond(), Boolean.FALSE); 917 } 918 919 return null; 920 } 921 922 public int getDynamicIdByStyle(StyleResourceValue resValue) { 923 if (mDynamicIdToStyleMap == null) { 924 // create the maps. 925 mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>(); 926 mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>(); 927 } 928 929 // look for an existing id 930 Integer id = mStyleToDynamicIdMap.get(resValue); 931 932 if (id == null) { 933 // generate a new id 934 id = ++mDynamicIdGenerator; 935 936 // and add it to the maps. 937 mDynamicIdToStyleMap.put(id, resValue); 938 mStyleToDynamicIdMap.put(resValue, id); 939 } 940 941 return id; 942 } 943 944 private StyleResourceValue getStyleByDynamicId(int i) { 945 if (mDynamicIdToStyleMap != null) { 946 return mDynamicIdToStyleMap.get(i); 947 } 948 949 return null; 950 } 951 952 public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) { 953 if (getRenderResources().getFrameworkResource(resType, resName) != null) { 954 // Bridge.getResourceId creates a new resource id if an existing one isn't found. So, 955 // we check for the existence of the resource before calling it. 956 return Bridge.getResourceId(resType, resName); 957 } 958 959 return defValue; 960 } 961 962 public int getProjectResourceValue(ResourceType resType, String resName, int defValue) { 963 // getResourceId creates a new resource id if an existing resource id isn't found. So, we 964 // check for the existence of the resource before calling it. 965 if (getRenderResources().getProjectResource(resType, resName) != null) { 966 if (mLayoutlibCallback != null) { 967 Integer value = mLayoutlibCallback.getResourceId(resType, resName); 968 if (value != null) { 969 return value; 970 } 971 } 972 } 973 974 return defValue; 975 } 976 977 public static Context getBaseContext(Context context) { 978 while (context instanceof ContextWrapper) { 979 context = ((ContextWrapper) context).getBaseContext(); 980 } 981 return context; 982 } 983 984 //------------ NOT OVERRIDEN -------------------- 985 986 @Override 987 public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) { 988 // pass 989 return false; 990 } 991 992 @Override 993 public int checkCallingOrSelfPermission(String arg0) { 994 // pass 995 return 0; 996 } 997 998 @Override 999 public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) { 1000 // pass 1001 return 0; 1002 } 1003 1004 @Override 1005 public int checkCallingPermission(String arg0) { 1006 // pass 1007 return 0; 1008 } 1009 1010 @Override 1011 public int checkCallingUriPermission(Uri arg0, int arg1) { 1012 // pass 1013 return 0; 1014 } 1015 1016 @Override 1017 public int checkPermission(String arg0, int arg1, int arg2) { 1018 // pass 1019 return 0; 1020 } 1021 1022 @Override 1023 public int checkSelfPermission(String arg0) { 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 public void sendBroadcastAsUser(Intent intent, UserHandle user, 1409 String receiverPermission, int appOp) { 1410 // pass 1411 } 1412 1413 @Override 1414 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1415 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 1416 int initialCode, String initialData, Bundle initialExtras) { 1417 // pass 1418 } 1419 1420 @Override 1421 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1422 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 1423 Handler scheduler, 1424 int initialCode, String initialData, Bundle initialExtras) { 1425 // pass 1426 } 1427 1428 @Override 1429 public void sendStickyBroadcast(Intent arg0) { 1430 // pass 1431 1432 } 1433 1434 @Override 1435 public void sendStickyOrderedBroadcast(Intent intent, 1436 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, 1437 Bundle initialExtras) { 1438 // pass 1439 } 1440 1441 @Override 1442 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { 1443 // pass 1444 } 1445 1446 @Override 1447 public void sendStickyOrderedBroadcastAsUser(Intent intent, 1448 UserHandle user, BroadcastReceiver resultReceiver, 1449 Handler scheduler, int initialCode, String initialData, 1450 Bundle initialExtras) { 1451 // pass 1452 } 1453 1454 @Override 1455 public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { 1456 // pass 1457 } 1458 1459 @Override 1460 public void setTheme(int arg0) { 1461 // pass 1462 1463 } 1464 1465 @Override 1466 public void setWallpaper(Bitmap arg0) throws IOException { 1467 // pass 1468 1469 } 1470 1471 @Override 1472 public void setWallpaper(InputStream arg0) throws IOException { 1473 // pass 1474 1475 } 1476 1477 @Override 1478 public void startActivity(Intent arg0) { 1479 // pass 1480 } 1481 1482 @Override 1483 public void startActivity(Intent arg0, Bundle arg1) { 1484 // pass 1485 } 1486 1487 @Override 1488 public void startIntentSender(IntentSender intent, 1489 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) 1490 throws IntentSender.SendIntentException { 1491 // pass 1492 } 1493 1494 @Override 1495 public void startIntentSender(IntentSender intent, 1496 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, 1497 Bundle options) throws IntentSender.SendIntentException { 1498 // pass 1499 } 1500 1501 @Override 1502 public boolean startInstrumentation(ComponentName arg0, String arg1, 1503 Bundle arg2) { 1504 // pass 1505 return false; 1506 } 1507 1508 @Override 1509 public ComponentName startService(Intent arg0) { 1510 // pass 1511 return null; 1512 } 1513 1514 @Override 1515 public boolean stopService(Intent arg0) { 1516 // pass 1517 return false; 1518 } 1519 1520 @Override 1521 public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) { 1522 // pass 1523 return null; 1524 } 1525 1526 @Override 1527 public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) { 1528 // pass 1529 return false; 1530 } 1531 1532 @Override 1533 public void unbindService(ServiceConnection arg0) { 1534 // pass 1535 1536 } 1537 1538 @Override 1539 public void unregisterReceiver(BroadcastReceiver arg0) { 1540 // pass 1541 1542 } 1543 1544 @Override 1545 public Context getApplicationContext() { 1546 return this; 1547 } 1548 1549 @Override 1550 public void startActivities(Intent[] arg0) { 1551 // pass 1552 1553 } 1554 1555 @Override 1556 public void startActivities(Intent[] arg0, Bundle arg1) { 1557 // pass 1558 1559 } 1560 1561 @Override 1562 public boolean isRestricted() { 1563 return false; 1564 } 1565 1566 @Override 1567 public File getObbDir() { 1568 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null); 1569 return null; 1570 } 1571 1572 @Override 1573 public DisplayAdjustments getDisplayAdjustments(int displayId) { 1574 // pass 1575 return null; 1576 } 1577 1578 @Override 1579 public int getUserId() { 1580 return 0; // not used 1581 } 1582 1583 @Override 1584 public File[] getExternalFilesDirs(String type) { 1585 // pass 1586 return new File[0]; 1587 } 1588 1589 @Override 1590 public File[] getObbDirs() { 1591 // pass 1592 return new File[0]; 1593 } 1594 1595 @Override 1596 public File[] getExternalCacheDirs() { 1597 // pass 1598 return new File[0]; 1599 } 1600 1601 @Override 1602 public File[] getExternalMediaDirs() { 1603 // pass 1604 return new File[0]; 1605 } 1606} 1607