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