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