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