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