BridgeContext.java revision 44e63a218cf8fcab9b4418246a512bd0b0c9157b
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.Resources.Theme;
53import android.content.res.TypedArray;
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.Map.Entry;
82import java.util.TreeMap;
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(null,
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        boolean useFrameworkNS = frameworkAttributes.get();
619        if (useFrameworkNS == false) {
620            // need to use the application namespace
621            namespace = mProjectCallback.getNamespace();
622        }
623
624        if (styleNameMap != null) {
625            for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) {
626                int index = styleAttribute.getKey().intValue();
627
628                String name = styleAttribute.getValue();
629                String value = null;
630                if (set != null) {
631                    value = set.getAttributeValue(namespace, name);
632
633                    // if this is an app attribute, and the first get fails, try with the
634                    // new res-auto namespace as well
635                    if (useFrameworkNS == false && value == null) {
636                        value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, name);
637                    }
638                }
639
640                // if there's no direct value for this attribute in the XML, we look for default
641                // values in the widget defStyle, and then in the theme.
642                if (value == null) {
643                    ResourceValue resValue = null;
644
645                    // look for the value in the custom style first (and its parent if needed)
646                    if (customStyleValues != null) {
647                        resValue = mRenderResources.findItemInStyle(customStyleValues, name);
648                    }
649
650                    // then look for the value in the default Style (and its parent if needed)
651                    if (resValue == null && defStyleValues != null) {
652                        resValue = mRenderResources.findItemInStyle(defStyleValues, name);
653                    }
654
655                    // if the item is not present in the defStyle, we look in the main theme (and
656                    // its parent themes)
657                    if (resValue == null) {
658                        resValue = mRenderResources.findItemInTheme(name);
659                    }
660
661                    // if we found a value, we make sure this doesn't reference another value.
662                    // So we resolve it.
663                    if (resValue != null) {
664                        // put the first default value, before the resolution.
665                        if (defaultPropMap != null) {
666                            defaultPropMap.put(name, resValue.getValue());
667                        }
668
669                        resValue = mRenderResources.resolveResValue(resValue);
670                    }
671
672                    ta.bridgeSetValue(index, name, resValue);
673                } else {
674                    // there is a value in the XML, but we need to resolve it in case it's
675                    // referencing another resource or a theme value.
676                    ta.bridgeSetValue(index, name,
677                            mRenderResources.resolveValue(null, name, value, isPlatformFile));
678                }
679            }
680        }
681
682        ta.sealArray();
683
684        return ta;
685    }
686
687    @Override
688    public Looper getMainLooper() {
689        return Looper.myLooper();
690    }
691
692
693    // ------------- private new methods
694
695    /**
696     * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
697     * values found in the given style.
698     * @see #obtainStyledAttributes(int, int[])
699     */
700    private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
701            throws Resources.NotFoundException {
702
703        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
704                false, true, null);
705
706        // for each attribute, get its name so that we can search it in the style
707        for (int i = 0 ; i < attrs.length ; i++) {
708            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
709            if (resolvedResource != null) {
710                String attrName = resolvedResource.getSecond();
711                // look for the value in the given style
712                ResourceValue resValue = mRenderResources.findItemInStyle(style, attrName);
713
714                if (resValue != null) {
715                    // resolve it to make sure there are no references left.
716                    ta.bridgeSetValue(i, attrName, mRenderResources.resolveResValue(resValue));
717
718                    resValue = mRenderResources.resolveResValue(resValue);
719                }
720            }
721        }
722
723        ta.sealArray();
724
725        return ta;
726    }
727
728
729    /**
730     * The input int[] attrs is one of com.android.internal.R.styleable fields where the name
731     * of the field is the style being referenced and the array contains one index per attribute.
732     * <p/>
733     * searchAttrs() finds all the names of the attributes referenced so for example if
734     * attrs == com.android.internal.R.styleable.View, this returns the list of the "xyz" where
735     * there's a field com.android.internal.R.styleable.View_xyz and the field value is the index
736     * that is used to reference the attribute later in the TypedArray.
737     *
738     * @param attrs An attribute array reference given to obtainStyledAttributes.
739     * @param outFrameworkFlag out value indicating if the attr array is a framework value
740     * @param outAttrName out value for the resolved attr name.
741     * @return A sorted map Attribute-Value to Attribute-Name for all attributes declared by the
742     *         attribute array. Returns null if nothing is found.
743     */
744    private TreeMap<Integer,String> searchAttrs(int[] attrs, AtomicBoolean outFrameworkFlag,
745            AtomicReference<String> outAttrName) {
746        // get the name of the array from the framework resources
747        String arrayName = Bridge.resolveResourceId(attrs);
748        if (arrayName != null) {
749            // if we found it, get the name of each of the int in the array.
750            TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
751            for (int i = 0 ; i < attrs.length ; i++) {
752                Pair<ResourceType, String> info = Bridge.resolveResourceId(attrs[i]);
753                if (info != null) {
754                    attributes.put(i, info.getSecond());
755                } else {
756                    // FIXME Not sure what we should be doing here...
757                    attributes.put(i, null);
758                }
759            }
760
761            if (outFrameworkFlag != null) {
762                outFrameworkFlag.set(true);
763            }
764            if (outAttrName != null) {
765                outAttrName.set(arrayName);
766            }
767
768            return attributes;
769        }
770
771        // if the name was not found in the framework resources, look in the project
772        // resources
773        arrayName = mProjectCallback.resolveResourceId(attrs);
774        if (arrayName != null) {
775            TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
776            for (int i = 0 ; i < attrs.length ; i++) {
777                Pair<ResourceType, String> info = mProjectCallback.resolveResourceId(attrs[i]);
778                if (info != null) {
779                    attributes.put(i, info.getSecond());
780                } else {
781                    // FIXME Not sure what we should be doing here...
782                    attributes.put(i, null);
783                }
784            }
785
786            if (outFrameworkFlag != null) {
787                outFrameworkFlag.set(false);
788            }
789            if (outAttrName != null) {
790                outAttrName.set(arrayName);
791            }
792
793            return attributes;
794        }
795
796        return null;
797    }
798
799    /**
800     * Searches for the attribute referenced by its internal id.
801     *
802     * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
803     * @return The unique name of the attribute, if found, e.g. "buttonStyle". Returns null
804     *         if nothing is found.
805     */
806    public String searchAttr(int attr) {
807        Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
808        if (info != null) {
809            return info.getSecond();
810        }
811
812        info = mProjectCallback.resolveResourceId(attr);
813        if (info != null) {
814            return info.getSecond();
815        }
816
817        return null;
818    }
819
820    public int getDynamicIdByStyle(StyleResourceValue resValue) {
821        if (mDynamicIdToStyleMap == null) {
822            // create the maps.
823            mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
824            mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
825        }
826
827        // look for an existing id
828        Integer id = mStyleToDynamicIdMap.get(resValue);
829
830        if (id == null) {
831            // generate a new id
832            id = Integer.valueOf(++mDynamicIdGenerator);
833
834            // and add it to the maps.
835            mDynamicIdToStyleMap.put(id, resValue);
836            mStyleToDynamicIdMap.put(resValue, id);
837        }
838
839        return id;
840    }
841
842    private StyleResourceValue getStyleByDynamicId(int i) {
843        if (mDynamicIdToStyleMap != null) {
844            return mDynamicIdToStyleMap.get(i);
845        }
846
847        return null;
848    }
849
850    public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
851        Integer value = Bridge.getResourceId(resType, resName);
852        if (value != null) {
853            return value.intValue();
854        }
855
856        return defValue;
857    }
858
859    public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
860        if (mProjectCallback != null) {
861            Integer value = mProjectCallback.getResourceId(resType, resName);
862            if (value != null) {
863                return value.intValue();
864            }
865        }
866
867        return defValue;
868    }
869
870    //------------ NOT OVERRIDEN --------------------
871
872    @Override
873    public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
874        // TODO Auto-generated method stub
875        return false;
876    }
877
878    @Override
879    public int checkCallingOrSelfPermission(String arg0) {
880        // TODO Auto-generated method stub
881        return 0;
882    }
883
884    @Override
885    public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
886        // TODO Auto-generated method stub
887        return 0;
888    }
889
890    @Override
891    public int checkCallingPermission(String arg0) {
892        // TODO Auto-generated method stub
893        return 0;
894    }
895
896    @Override
897    public int checkCallingUriPermission(Uri arg0, int arg1) {
898        // TODO Auto-generated method stub
899        return 0;
900    }
901
902    @Override
903    public int checkPermission(String arg0, int arg1, int arg2) {
904        // TODO Auto-generated method stub
905        return 0;
906    }
907
908    @Override
909    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
910        // TODO Auto-generated method stub
911        return 0;
912    }
913
914    @Override
915    public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
916            int arg4, int arg5) {
917        // TODO Auto-generated method stub
918        return 0;
919    }
920
921    @Override
922    public void clearWallpaper() {
923        // TODO Auto-generated method stub
924
925    }
926
927    @Override
928    public Context createPackageContext(String arg0, int arg1) {
929        // TODO Auto-generated method stub
930        return null;
931    }
932
933    @Override
934    public String[] databaseList() {
935        // TODO Auto-generated method stub
936        return null;
937    }
938
939    @Override
940    public boolean deleteDatabase(String arg0) {
941        // TODO Auto-generated method stub
942        return false;
943    }
944
945    @Override
946    public boolean deleteFile(String arg0) {
947        // TODO Auto-generated method stub
948        return false;
949    }
950
951    @Override
952    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
953        // TODO Auto-generated method stub
954
955    }
956
957    @Override
958    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
959            String arg2) {
960        // TODO Auto-generated method stub
961
962    }
963
964    @Override
965    public void enforceCallingPermission(String arg0, String arg1) {
966        // TODO Auto-generated method stub
967
968    }
969
970    @Override
971    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
972        // TODO Auto-generated method stub
973
974    }
975
976    @Override
977    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
978        // TODO Auto-generated method stub
979
980    }
981
982    @Override
983    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
984            String arg4) {
985        // TODO Auto-generated method stub
986
987    }
988
989    @Override
990    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
991            int arg3, int arg4, int arg5, String arg6) {
992        // TODO Auto-generated method stub
993
994    }
995
996    @Override
997    public String[] fileList() {
998        // TODO Auto-generated method stub
999        return null;
1000    }
1001
1002    @Override
1003    public AssetManager getAssets() {
1004        // TODO Auto-generated method stub
1005        return null;
1006    }
1007
1008    @Override
1009    public File getCacheDir() {
1010        // TODO Auto-generated method stub
1011        return null;
1012    }
1013
1014    @Override
1015    public File getExternalCacheDir() {
1016        // TODO Auto-generated method stub
1017        return null;
1018    }
1019
1020    @Override
1021    public ContentResolver getContentResolver() {
1022        if (mContentResolver == null) {
1023            mContentResolver = new BridgeContentResolver(this);
1024        }
1025        return mContentResolver;
1026    }
1027
1028    @Override
1029    public File getDatabasePath(String arg0) {
1030        // TODO Auto-generated method stub
1031        return null;
1032    }
1033
1034    @Override
1035    public File getDir(String arg0, int arg1) {
1036        // TODO Auto-generated method stub
1037        return null;
1038    }
1039
1040    @Override
1041    public File getFileStreamPath(String arg0) {
1042        // TODO Auto-generated method stub
1043        return null;
1044    }
1045
1046    @Override
1047    public File getFilesDir() {
1048        // TODO Auto-generated method stub
1049        return null;
1050    }
1051
1052    @Override
1053    public File getExternalFilesDir(String type) {
1054        // TODO Auto-generated method stub
1055        return null;
1056    }
1057
1058    @Override
1059    public String getPackageCodePath() {
1060        // TODO Auto-generated method stub
1061        return null;
1062    }
1063
1064    @Override
1065    public PackageManager getPackageManager() {
1066        // TODO Auto-generated method stub
1067        return null;
1068    }
1069
1070    @Override
1071    public String getPackageName() {
1072        // TODO Auto-generated method stub
1073        return null;
1074    }
1075
1076    @Override
1077    public ApplicationInfo getApplicationInfo() {
1078        return mApplicationInfo;
1079    }
1080
1081    @Override
1082    public String getPackageResourcePath() {
1083        // TODO Auto-generated method stub
1084        return null;
1085    }
1086
1087    @Override
1088    public File getSharedPrefsFile(String name) {
1089        // TODO Auto-generated method stub
1090        return null;
1091    }
1092
1093    @Override
1094    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1095        // TODO Auto-generated method stub
1096        return null;
1097    }
1098
1099    @Override
1100    public Drawable getWallpaper() {
1101        // TODO Auto-generated method stub
1102        return null;
1103    }
1104
1105    @Override
1106    public int getWallpaperDesiredMinimumWidth() {
1107        return -1;
1108    }
1109
1110    @Override
1111    public int getWallpaperDesiredMinimumHeight() {
1112        return -1;
1113    }
1114
1115    @Override
1116    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1117        // TODO Auto-generated method stub
1118
1119    }
1120
1121    @Override
1122    public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1123        // TODO Auto-generated method stub
1124        return null;
1125    }
1126
1127    @Override
1128    public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1129        // TODO Auto-generated method stub
1130        return null;
1131    }
1132
1133    @Override
1134    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1135        // TODO Auto-generated method stub
1136        return null;
1137    }
1138
1139    @Override
1140    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1141            CursorFactory arg2, DatabaseErrorHandler arg3) {
1142        // TODO Auto-generated method stub
1143        return null;
1144    }
1145
1146    @Override
1147    public Drawable peekWallpaper() {
1148        // TODO Auto-generated method stub
1149        return null;
1150    }
1151
1152    @Override
1153    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1154        // TODO Auto-generated method stub
1155        return null;
1156    }
1157
1158    @Override
1159    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1160            String arg2, Handler arg3) {
1161        // TODO Auto-generated method stub
1162        return null;
1163    }
1164
1165    @Override
1166    public void removeStickyBroadcast(Intent arg0) {
1167        // TODO Auto-generated method stub
1168
1169    }
1170
1171    @Override
1172    public void revokeUriPermission(Uri arg0, int arg1) {
1173        // TODO Auto-generated method stub
1174
1175    }
1176
1177    @Override
1178    public void sendBroadcast(Intent arg0) {
1179        // TODO Auto-generated method stub
1180
1181    }
1182
1183    @Override
1184    public void sendBroadcast(Intent arg0, String arg1) {
1185        // TODO Auto-generated method stub
1186
1187    }
1188
1189    @Override
1190    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1191        // TODO Auto-generated method stub
1192
1193    }
1194
1195    @Override
1196    public void sendOrderedBroadcast(Intent arg0, String arg1,
1197            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1198            Bundle arg6) {
1199        // TODO Auto-generated method stub
1200
1201    }
1202
1203    @Override
1204    public void sendStickyBroadcast(Intent arg0) {
1205        // TODO Auto-generated method stub
1206
1207    }
1208
1209    @Override
1210    public void sendStickyOrderedBroadcast(Intent intent,
1211            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1212           Bundle initialExtras) {
1213        // TODO Auto-generated method stub
1214    }
1215
1216    @Override
1217    public void setTheme(int arg0) {
1218        // TODO Auto-generated method stub
1219
1220    }
1221
1222    @Override
1223    public void setWallpaper(Bitmap arg0) throws IOException {
1224        // TODO Auto-generated method stub
1225
1226    }
1227
1228    @Override
1229    public void setWallpaper(InputStream arg0) throws IOException {
1230        // TODO Auto-generated method stub
1231
1232    }
1233
1234    @Override
1235    public void startActivity(Intent arg0) {
1236        // TODO Auto-generated method stub
1237
1238    }
1239
1240    @Override
1241    public void startIntentSender(IntentSender intent,
1242            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1243            throws IntentSender.SendIntentException {
1244        // TODO Auto-generated method stub
1245    }
1246
1247    @Override
1248    public boolean startInstrumentation(ComponentName arg0, String arg1,
1249            Bundle arg2) {
1250        // TODO Auto-generated method stub
1251        return false;
1252    }
1253
1254    @Override
1255    public ComponentName startService(Intent arg0) {
1256        // TODO Auto-generated method stub
1257        return null;
1258    }
1259
1260    @Override
1261    public boolean stopService(Intent arg0) {
1262        // TODO Auto-generated method stub
1263        return false;
1264    }
1265
1266    @Override
1267    public void unbindService(ServiceConnection arg0) {
1268        // TODO Auto-generated method stub
1269
1270    }
1271
1272    @Override
1273    public void unregisterReceiver(BroadcastReceiver arg0) {
1274        // TODO Auto-generated method stub
1275
1276    }
1277
1278    @Override
1279    public Context getApplicationContext() {
1280        return this;
1281    }
1282
1283    @Override
1284    public void startActivities(Intent[] arg0) {
1285        // TODO Auto-generated method stub
1286
1287    }
1288
1289    @Override
1290    public boolean isRestricted() {
1291        return false;
1292    }
1293
1294    @Override
1295    public File getObbDir() {
1296        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1297        return null;
1298    }
1299}
1300