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