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