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