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