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