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