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