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