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