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