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