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