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