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