BridgeContext.java revision 56222cfbe9973c518f7e8c9113c614de80b5a4b2
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(BridgeConstants.TAG_BROKEN, 340 "Parser is not a BridgeXmlBlockParser!"); 341 return null; 342 } 343 344 boolean[] frameworkAttributes = new boolean[1]; 345 TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes); 346 347 BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length, 348 isPlatformFile); 349 350 // resolve the defStyleAttr value into a IStyleResourceValue 351 StyleResourceValue defStyleValues = null; 352 353 // look for a custom style. 354 String customStyle = null; 355 if (set != null) { 356 customStyle = set.getAttributeValue(null /* namespace*/, "style"); 357 } 358 if (customStyle != null) { 359 ResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/); 360 361 if (item instanceof StyleResourceValue) { 362 defStyleValues = (StyleResourceValue)item; 363 } 364 } 365 366 if (defStyleValues == null && defStyleAttr != 0) { 367 // get the name from the int. 368 String defStyleName = searchAttr(defStyleAttr); 369 370 if (defaultPropMap != null) { 371 defaultPropMap.put("style", defStyleName); 372 } 373 374 // look for the style in the current theme, and its parent: 375 if (mThemeValues != null) { 376 ResourceValue item = findItemInStyle(mThemeValues, defStyleName); 377 378 if (item != null) { 379 // item is a reference to a style entry. Search for it. 380 item = findResValue(item.getValue(), false /*forceFrameworkOnly*/); 381 382 if (item instanceof StyleResourceValue) { 383 defStyleValues = (StyleResourceValue)item; 384 } 385 } else { 386 Bridge.getLog().error(null, 387 String.format( 388 "Failed to find style '%s' in current theme", defStyleName)); 389 } 390 } 391 } 392 393 if (defStyleRes != 0) { 394 // FIXME: See what we need to do with this. 395 throw new UnsupportedOperationException(); 396 } 397 398 String namespace = BridgeConstants.NS_RESOURCES; 399 if (frameworkAttributes[0] == false) { 400 // need to use the application namespace 401 namespace = mProjectCallback.getNamespace(); 402 } 403 404 if (styleNameMap != null) { 405 for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) { 406 int index = styleAttribute.getKey().intValue(); 407 408 String name = styleAttribute.getValue(); 409 String value = null; 410 if (set != null) { 411 value = set.getAttributeValue(namespace, name); 412 } 413 414 // if there's no direct value for this attribute in the XML, we look for default 415 // values in the widget defStyle, and then in the theme. 416 if (value == null) { 417 ResourceValue resValue = null; 418 419 // look for the value in the defStyle first (and its parent if needed) 420 if (defStyleValues != null) { 421 resValue = findItemInStyle(defStyleValues, name); 422 } 423 424 // if the item is not present in the defStyle, we look in the main theme (and 425 // its parent themes) 426 if (resValue == null && mThemeValues != null) { 427 resValue = findItemInStyle(mThemeValues, name); 428 } 429 430 // if we found a value, we make sure this doesn't reference another value. 431 // So we resolve it. 432 if (resValue != null) { 433 // put the first default value, before the resolution. 434 if (defaultPropMap != null) { 435 defaultPropMap.put(name, resValue.getValue()); 436 } 437 438 resValue = resolveResValue(resValue); 439 } 440 441 ta.bridgeSetValue(index, name, resValue); 442 } else { 443 // there is a value in the XML, but we need to resolve it in case it's 444 // referencing another resource or a theme value. 445 ta.bridgeSetValue(index, name, resolveValue(null, name, value)); 446 } 447 } 448 } 449 450 ta.sealArray(); 451 452 return ta; 453 } 454 455 @Override 456 public Looper getMainLooper() { 457 return Looper.myLooper(); 458 } 459 460 461 // ------------- private new methods 462 463 /** 464 * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the 465 * values found in the given style. 466 * @see #obtainStyledAttributes(int, int[]) 467 */ 468 private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs) 469 throws Resources.NotFoundException { 470 TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null); 471 472 BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length, 473 false /* platformResourceFlag */); 474 475 // loop through all the values in the style map, and init the TypedArray with 476 // the style we got from the dynamic id 477 for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) { 478 int index = styleAttribute.getKey().intValue(); 479 480 String name = styleAttribute.getValue(); 481 482 // get the value from the style, or its parent styles. 483 ResourceValue resValue = findItemInStyle(style, name); 484 485 // resolve it to make sure there are no references left. 486 ta.bridgeSetValue(index, name, resolveResValue(resValue)); 487 } 488 489 ta.sealArray(); 490 491 return ta; 492 } 493 494 495 /** 496 * Resolves the value of a resource, if the value references a theme or resource value. 497 * <p/> 498 * This method ensures that it returns a {@link ResourceValue} object that does not 499 * reference another resource. 500 * If the resource cannot be resolved, it returns <code>null</code>. 501 * <p/> 502 * If a value that does not need to be resolved is given, the method will return a new 503 * instance of {@link ResourceValue} that contains the input value. 504 * 505 * @param type the type of the resource 506 * @param name the name of the attribute containing this value. 507 * @param value the resource value, or reference to resolve 508 * @return the resolved resource value or <code>null</code> if it failed to resolve it. 509 */ 510 private ResourceValue resolveValue(String type, String name, String value) { 511 if (value == null) { 512 return null; 513 } 514 515 // get the ResourceValue referenced by this value 516 ResourceValue resValue = findResValue(value, false /*forceFrameworkOnly*/); 517 518 // if resValue is null, but value is not null, this means it was not a reference. 519 // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't 520 // matter. 521 if (resValue == null) { 522 return new ResourceValue(type, name, value, false /*isFramework*/); 523 } 524 525 // we resolved a first reference, but we need to make sure this isn't a reference also. 526 return resolveResValue(resValue); 527 } 528 529 /** 530 * Returns the {@link ResourceValue} referenced by the value of <var>value</var>. 531 * <p/> 532 * This method ensures that it returns a {@link ResourceValue} object that does not 533 * reference another resource. 534 * If the resource cannot be resolved, it returns <code>null</code>. 535 * <p/> 536 * If a value that does not need to be resolved is given, the method will return the input 537 * value. 538 * 539 * @param value the value containing the reference to resolve. 540 * @return a {@link ResourceValue} object or <code>null</code> 541 */ 542 public ResourceValue resolveResValue(ResourceValue value) { 543 if (value == null) { 544 return null; 545 } 546 547 // if the resource value is a style, we simply return it. 548 if (value instanceof StyleResourceValue) { 549 return value; 550 } 551 552 // else attempt to find another ResourceValue referenced by this one. 553 ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework()); 554 555 // if the value did not reference anything, then we simply return the input value 556 if (resolvedValue == null) { 557 return value; 558 } 559 560 // otherwise, we attempt to resolve this new value as well 561 return resolveResValue(resolvedValue); 562 } 563 564 /** 565 * Searches for, and returns a {@link ResourceValue} by its reference. 566 * <p/> 567 * The reference format can be: 568 * <pre>@resType/resName</pre> 569 * <pre>@android:resType/resName</pre> 570 * <pre>@resType/android:resName</pre> 571 * <pre>?resType/resName</pre> 572 * <pre>?android:resType/resName</pre> 573 * <pre>?resType/android:resName</pre> 574 * Any other string format will return <code>null</code>. 575 * <p/> 576 * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method 577 * only support the android namespace. 578 * 579 * @param reference the resource reference to search for. 580 * @param forceFrameworkOnly if true all references are considered to be toward framework 581 * resource even if the reference does not include the android: prefix. 582 * @return a {@link ResourceValue} or <code>null</code>. 583 */ 584 ResourceValue findResValue(String reference, boolean forceFrameworkOnly) { 585 if (reference == null) { 586 return null; 587 } 588 if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) { 589 // no theme? no need to go further! 590 if (mThemeValues == null) { 591 return null; 592 } 593 594 boolean frameworkOnly = false; 595 596 // eliminate the prefix from the string 597 if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) { 598 frameworkOnly = true; 599 reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length()); 600 } else { 601 reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length()); 602 } 603 604 // at this point, value can contain type/name (drawable/foo for instance). 605 // split it to make sure. 606 String[] segments = reference.split("\\/"); 607 608 // we look for the referenced item name. 609 String referenceName = null; 610 611 if (segments.length == 2) { 612 // there was a resType in the reference. If it's attr, we ignore it 613 // else, we assert for now. 614 if (BridgeConstants.RES_ATTR.equals(segments[0])) { 615 referenceName = segments[1]; 616 } else { 617 // At this time, no support for ?type/name where type is not "attr" 618 return null; 619 } 620 } else { 621 // it's just an item name. 622 referenceName = segments[0]; 623 } 624 625 // now we look for android: in the referenceName in order to support format 626 // such as: ?attr/android:name 627 if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) { 628 frameworkOnly = true; 629 referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length()); 630 } 631 632 // Now look for the item in the theme, starting with the current one. 633 if (frameworkOnly) { 634 // FIXME for now we do the same as if it didn't specify android: 635 return findItemInStyle(mThemeValues, referenceName); 636 } 637 638 return findItemInStyle(mThemeValues, referenceName); 639 } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) { 640 boolean frameworkOnly = false; 641 642 // check for the specific null reference value. 643 if (BridgeConstants.REFERENCE_NULL.equals(reference)) { 644 return null; 645 } 646 647 // Eliminate the prefix from the string. 648 if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) { 649 frameworkOnly = true; 650 reference = reference.substring( 651 BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length()); 652 } else { 653 reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length()); 654 } 655 656 // at this point, value contains type/[android:]name (drawable/foo for instance) 657 String[] segments = reference.split("\\/"); 658 659 // now we look for android: in the resource name in order to support format 660 // such as: @drawable/android:name 661 if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) { 662 frameworkOnly = true; 663 segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length()); 664 } 665 666 return findResValue(segments[0], segments[1], 667 forceFrameworkOnly ? true :frameworkOnly); 668 } 669 670 // Looks like the value didn't reference anything. Return null. 671 return null; 672 } 673 674 /** 675 * Searches for, and returns a {@link ResourceValue} by its name, and type. 676 * @param resType the type of the resource 677 * @param resName the name of the resource 678 * @param frameworkOnly if <code>true</code>, the method does not search in the 679 * project resources 680 */ 681 private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) { 682 // map of ResouceValue for the given type 683 Map<String, ResourceValue> typeMap; 684 685 // if allowed, search in the project resources first. 686 if (frameworkOnly == false) { 687 typeMap = mProjectResources.get(resType); 688 if (typeMap != null) { 689 ResourceValue item = typeMap.get(resName); 690 if (item != null) { 691 return item; 692 } 693 } 694 } 695 696 // now search in the framework resources. 697 typeMap = mFrameworkResources.get(resType); 698 if (typeMap != null) { 699 ResourceValue item = typeMap.get(resName); 700 if (item != null) { 701 return item; 702 } 703 } 704 705 // didn't find the resource anywhere. 706 // This is normal if the resource is an ID that is generated automatically. 707 // For other resources, we output a warning 708 if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$ 709 Bridge.getLog().warning(BridgeConstants.TAG_RESOURCES_RESOLVE, 710 "Couldn't resolve resource @" + 711 (frameworkOnly ? "android:" : "") + resType + "/" + resName); 712 } 713 return null; 714 } 715 716 /** 717 * Returns a framework resource by type and name. The returned resource is resolved. 718 * @param resourceType the type of the resource 719 * @param resourceName the name of the resource 720 */ 721 public ResourceValue getFrameworkResource(String resourceType, String resourceName) { 722 return getResource(resourceType, resourceName, mFrameworkResources); 723 } 724 725 /** 726 * Returns a project resource by type and name. The returned resource is resolved. 727 * @param resourceType the type of the resource 728 * @param resourceName the name of the resource 729 */ 730 public ResourceValue getProjectResource(String resourceType, String resourceName) { 731 return getResource(resourceType, resourceName, mProjectResources); 732 } 733 734 ResourceValue getResource(String resourceType, String resourceName, 735 Map<String, Map<String, ResourceValue>> resourceRepository) { 736 Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType); 737 if (typeMap != null) { 738 ResourceValue item = typeMap.get(resourceName); 739 if (item != null) { 740 item = resolveResValue(item); 741 return item; 742 } 743 } 744 745 // didn't find the resource anywhere. 746 return null; 747 748 } 749 750 /** 751 * Returns the {@link ResourceValue} matching a given name in a given style. If the 752 * item is not directly available in the style, the method looks in its parent style. 753 * @param style the style to search in 754 * @param itemName the name of the item to search for. 755 * @return the {@link ResourceValue} object or <code>null</code> 756 */ 757 public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) { 758 ResourceValue item = style.findValue(itemName); 759 760 // if we didn't find it, we look in the parent style (if applicable) 761 if (item == null && mStyleInheritanceMap != null) { 762 StyleResourceValue parentStyle = mStyleInheritanceMap.get(style); 763 if (parentStyle != null) { 764 return findItemInStyle(parentStyle, itemName); 765 } 766 } 767 768 return item; 769 } 770 771 /** 772 * The input int[] attrs is one of com.android.internal.R.styleable fields where the name 773 * of the field is the style being referenced and the array contains one index per attribute. 774 * <p/> 775 * searchAttrs() finds all the names of the attributes referenced so for example if 776 * attrs == com.android.internal.R.styleable.View, this returns the list of the "xyz" where 777 * there's a field com.android.internal.R.styleable.View_xyz and the field value is the index 778 * that is used to reference the attribute later in the TypedArray. 779 * 780 * @param attrs An attribute array reference given to obtainStyledAttributes. 781 * @return A sorted map Attribute-Value to Attribute-Name for all attributes declared by the 782 * attribute array. Returns null if nothing is found. 783 */ 784 private TreeMap<Integer,String> searchAttrs(int[] attrs, boolean[] outFrameworkFlag) { 785 // get the name of the array from the framework resources 786 String arrayName = Bridge.resolveResourceValue(attrs); 787 if (arrayName != null) { 788 // if we found it, get the name of each of the int in the array. 789 TreeMap<Integer,String> attributes = new TreeMap<Integer, String>(); 790 for (int i = 0 ; i < attrs.length ; i++) { 791 String[] info = Bridge.resolveResourceValue(attrs[i]); 792 if (info != null) { 793 attributes.put(i, info[0]); 794 } else { 795 // FIXME Not sure what we should be doing here... 796 attributes.put(i, null); 797 } 798 } 799 800 if (outFrameworkFlag != null) { 801 outFrameworkFlag[0] = true; 802 } 803 804 return attributes; 805 } 806 807 // if the name was not found in the framework resources, look in the project 808 // resources 809 arrayName = mProjectCallback.resolveResourceValue(attrs); 810 if (arrayName != null) { 811 TreeMap<Integer,String> attributes = new TreeMap<Integer, String>(); 812 for (int i = 0 ; i < attrs.length ; i++) { 813 String[] info = mProjectCallback.resolveResourceValue(attrs[i]); 814 if (info != null) { 815 attributes.put(i, info[0]); 816 } else { 817 // FIXME Not sure what we should be doing here... 818 attributes.put(i, null); 819 } 820 } 821 822 if (outFrameworkFlag != null) { 823 outFrameworkFlag[0] = false; 824 } 825 826 return attributes; 827 } 828 829 return null; 830 } 831 832 /** 833 * Searches for the attribute referenced by its internal id. 834 * 835 * @param attr An attribute reference given to obtainStyledAttributes such as defStyle. 836 * @return The unique name of the attribute, if found, e.g. "buttonStyle". Returns null 837 * if nothing is found. 838 */ 839 public String searchAttr(int attr) { 840 String[] info = Bridge.resolveResourceValue(attr); 841 if (info != null) { 842 return info[0]; 843 } 844 845 info = mProjectCallback.resolveResourceValue(attr); 846 if (info != null) { 847 return info[0]; 848 } 849 850 return null; 851 } 852 853 int getDynamicIdByStyle(StyleResourceValue resValue) { 854 if (mDynamicIdToStyleMap == null) { 855 // create the maps. 856 mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>(); 857 mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>(); 858 } 859 860 // look for an existing id 861 Integer id = mStyleToDynamicIdMap.get(resValue); 862 863 if (id == null) { 864 // generate a new id 865 id = Integer.valueOf(++mDynamicIdGenerator); 866 867 // and add it to the maps. 868 mDynamicIdToStyleMap.put(id, resValue); 869 mStyleToDynamicIdMap.put(resValue, id); 870 } 871 872 return id; 873 } 874 875 private StyleResourceValue getStyleByDynamicId(int i) { 876 if (mDynamicIdToStyleMap != null) { 877 return mDynamicIdToStyleMap.get(i); 878 } 879 880 return null; 881 } 882 883 int getFrameworkResourceValue(String resType, String resName, int defValue) { 884 Integer value = Bridge.getResourceValue(resType, resName); 885 if (value != null) { 886 return value.intValue(); 887 } 888 889 return defValue; 890 } 891 892 int getProjectResourceValue(String resType, String resName, int defValue) { 893 if (mProjectCallback != null) { 894 Integer value = mProjectCallback.getResourceValue(resType, resName); 895 if (value != null) { 896 return value.intValue(); 897 } 898 } 899 900 return defValue; 901 } 902 903 //------------ NOT OVERRIDEN -------------------- 904 905 @Override 906 public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) { 907 // TODO Auto-generated method stub 908 return false; 909 } 910 911 @Override 912 public int checkCallingOrSelfPermission(String arg0) { 913 // TODO Auto-generated method stub 914 return 0; 915 } 916 917 @Override 918 public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) { 919 // TODO Auto-generated method stub 920 return 0; 921 } 922 923 @Override 924 public int checkCallingPermission(String arg0) { 925 // TODO Auto-generated method stub 926 return 0; 927 } 928 929 @Override 930 public int checkCallingUriPermission(Uri arg0, int arg1) { 931 // TODO Auto-generated method stub 932 return 0; 933 } 934 935 @Override 936 public int checkPermission(String arg0, int arg1, int arg2) { 937 // TODO Auto-generated method stub 938 return 0; 939 } 940 941 @Override 942 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) { 943 // TODO Auto-generated method stub 944 return 0; 945 } 946 947 @Override 948 public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3, 949 int arg4, int arg5) { 950 // TODO Auto-generated method stub 951 return 0; 952 } 953 954 @Override 955 public void clearWallpaper() { 956 // TODO Auto-generated method stub 957 958 } 959 960 @Override 961 public Context createPackageContext(String arg0, int arg1) { 962 // TODO Auto-generated method stub 963 return null; 964 } 965 966 @Override 967 public String[] databaseList() { 968 // TODO Auto-generated method stub 969 return null; 970 } 971 972 @Override 973 public boolean deleteDatabase(String arg0) { 974 // TODO Auto-generated method stub 975 return false; 976 } 977 978 @Override 979 public boolean deleteFile(String arg0) { 980 // TODO Auto-generated method stub 981 return false; 982 } 983 984 @Override 985 public void enforceCallingOrSelfPermission(String arg0, String arg1) { 986 // TODO Auto-generated method stub 987 988 } 989 990 @Override 991 public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1, 992 String arg2) { 993 // TODO Auto-generated method stub 994 995 } 996 997 @Override 998 public void enforceCallingPermission(String arg0, String arg1) { 999 // TODO Auto-generated method stub 1000 1001 } 1002 1003 @Override 1004 public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) { 1005 // TODO Auto-generated method stub 1006 1007 } 1008 1009 @Override 1010 public void enforcePermission(String arg0, int arg1, int arg2, String arg3) { 1011 // TODO Auto-generated method stub 1012 1013 } 1014 1015 @Override 1016 public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3, 1017 String arg4) { 1018 // TODO Auto-generated method stub 1019 1020 } 1021 1022 @Override 1023 public void enforceUriPermission(Uri arg0, String arg1, String arg2, 1024 int arg3, int arg4, int arg5, String arg6) { 1025 // TODO Auto-generated method stub 1026 1027 } 1028 1029 @Override 1030 public String[] fileList() { 1031 // TODO Auto-generated method stub 1032 return null; 1033 } 1034 1035 @Override 1036 public AssetManager getAssets() { 1037 // TODO Auto-generated method stub 1038 return null; 1039 } 1040 1041 @Override 1042 public File getCacheDir() { 1043 // TODO Auto-generated method stub 1044 return null; 1045 } 1046 1047 @Override 1048 public File getExternalCacheDir() { 1049 // TODO Auto-generated method stub 1050 return null; 1051 } 1052 1053 @Override 1054 public ContentResolver getContentResolver() { 1055 if (mContentResolver == null) { 1056 mContentResolver = new BridgeContentResolver(this); 1057 } 1058 return mContentResolver; 1059 } 1060 1061 @Override 1062 public File getDatabasePath(String arg0) { 1063 // TODO Auto-generated method stub 1064 return null; 1065 } 1066 1067 @Override 1068 public File getDir(String arg0, int arg1) { 1069 // TODO Auto-generated method stub 1070 return null; 1071 } 1072 1073 @Override 1074 public File getFileStreamPath(String arg0) { 1075 // TODO Auto-generated method stub 1076 return null; 1077 } 1078 1079 @Override 1080 public File getFilesDir() { 1081 // TODO Auto-generated method stub 1082 return null; 1083 } 1084 1085 @Override 1086 public File getExternalFilesDir(String type) { 1087 // TODO Auto-generated method stub 1088 return null; 1089 } 1090 1091 @Override 1092 public String getPackageCodePath() { 1093 // TODO Auto-generated method stub 1094 return null; 1095 } 1096 1097 @Override 1098 public PackageManager getPackageManager() { 1099 // TODO Auto-generated method stub 1100 return null; 1101 } 1102 1103 @Override 1104 public String getPackageName() { 1105 // TODO Auto-generated method stub 1106 return null; 1107 } 1108 1109 @Override 1110 public ApplicationInfo getApplicationInfo() { 1111 return new ApplicationInfo(); 1112 } 1113 1114 @Override 1115 public String getPackageResourcePath() { 1116 // TODO Auto-generated method stub 1117 return null; 1118 } 1119 1120 @Override 1121 public File getSharedPrefsFile(String name) { 1122 // TODO Auto-generated method stub 1123 return null; 1124 } 1125 1126 @Override 1127 public SharedPreferences getSharedPreferences(String arg0, int arg1) { 1128 // TODO Auto-generated method stub 1129 return null; 1130 } 1131 1132 @Override 1133 public Drawable getWallpaper() { 1134 // TODO Auto-generated method stub 1135 return null; 1136 } 1137 1138 @Override 1139 public int getWallpaperDesiredMinimumWidth() { 1140 return -1; 1141 } 1142 1143 @Override 1144 public int getWallpaperDesiredMinimumHeight() { 1145 return -1; 1146 } 1147 1148 @Override 1149 public void grantUriPermission(String arg0, Uri arg1, int arg2) { 1150 // TODO Auto-generated method stub 1151 1152 } 1153 1154 @Override 1155 public FileInputStream openFileInput(String arg0) throws FileNotFoundException { 1156 // TODO Auto-generated method stub 1157 return null; 1158 } 1159 1160 @Override 1161 public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException { 1162 // TODO Auto-generated method stub 1163 return null; 1164 } 1165 1166 @Override 1167 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) { 1168 // TODO Auto-generated method stub 1169 return null; 1170 } 1171 1172 @Override 1173 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, 1174 CursorFactory arg2, DatabaseErrorHandler arg3) { 1175 // TODO Auto-generated method stub 1176 return null; 1177 } 1178 1179 @Override 1180 public Drawable peekWallpaper() { 1181 // TODO Auto-generated method stub 1182 return null; 1183 } 1184 1185 @Override 1186 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) { 1187 // TODO Auto-generated method stub 1188 return null; 1189 } 1190 1191 @Override 1192 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, 1193 String arg2, Handler arg3) { 1194 // TODO Auto-generated method stub 1195 return null; 1196 } 1197 1198 @Override 1199 public void removeStickyBroadcast(Intent arg0) { 1200 // TODO Auto-generated method stub 1201 1202 } 1203 1204 @Override 1205 public void revokeUriPermission(Uri arg0, int arg1) { 1206 // TODO Auto-generated method stub 1207 1208 } 1209 1210 @Override 1211 public void sendBroadcast(Intent arg0) { 1212 // TODO Auto-generated method stub 1213 1214 } 1215 1216 @Override 1217 public void sendBroadcast(Intent arg0, String arg1) { 1218 // TODO Auto-generated method stub 1219 1220 } 1221 1222 @Override 1223 public void sendOrderedBroadcast(Intent arg0, String arg1) { 1224 // TODO Auto-generated method stub 1225 1226 } 1227 1228 @Override 1229 public void sendOrderedBroadcast(Intent arg0, String arg1, 1230 BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, 1231 Bundle arg6) { 1232 // TODO Auto-generated method stub 1233 1234 } 1235 1236 @Override 1237 public void sendStickyBroadcast(Intent arg0) { 1238 // TODO Auto-generated method stub 1239 1240 } 1241 1242 @Override 1243 public void sendStickyOrderedBroadcast(Intent intent, 1244 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, 1245 Bundle initialExtras) { 1246 // TODO Auto-generated method stub 1247 } 1248 1249 @Override 1250 public void setTheme(int arg0) { 1251 // TODO Auto-generated method stub 1252 1253 } 1254 1255 @Override 1256 public void setWallpaper(Bitmap arg0) throws IOException { 1257 // TODO Auto-generated method stub 1258 1259 } 1260 1261 @Override 1262 public void setWallpaper(InputStream arg0) throws IOException { 1263 // TODO Auto-generated method stub 1264 1265 } 1266 1267 @Override 1268 public void startActivity(Intent arg0) { 1269 // TODO Auto-generated method stub 1270 1271 } 1272 1273 @Override 1274 public void startIntentSender(IntentSender intent, 1275 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) 1276 throws IntentSender.SendIntentException { 1277 // TODO Auto-generated method stub 1278 } 1279 1280 @Override 1281 public boolean startInstrumentation(ComponentName arg0, String arg1, 1282 Bundle arg2) { 1283 // TODO Auto-generated method stub 1284 return false; 1285 } 1286 1287 @Override 1288 public ComponentName startService(Intent arg0) { 1289 // TODO Auto-generated method stub 1290 return null; 1291 } 1292 1293 @Override 1294 public boolean stopService(Intent arg0) { 1295 // TODO Auto-generated method stub 1296 return false; 1297 } 1298 1299 @Override 1300 public void unbindService(ServiceConnection arg0) { 1301 // TODO Auto-generated method stub 1302 1303 } 1304 1305 @Override 1306 public void unregisterReceiver(BroadcastReceiver arg0) { 1307 // TODO Auto-generated method stub 1308 1309 } 1310 1311 @Override 1312 public Context getApplicationContext() { 1313 throw new UnsupportedOperationException(); 1314 } 1315 1316 @Override 1317 public void startActivities(Intent[] arg0) { 1318 // TODO Auto-generated method stub 1319 1320 } 1321 1322 @Override 1323 public boolean isRestricted() { 1324 return false; 1325 } 1326} 1327