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