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.android.view.WindowManagerImpl;
29import com.android.layoutlib.bridge.impl.ParserFactory;
30import com.android.layoutlib.bridge.impl.Stack;
31import com.android.resources.ResourceType;
32import com.android.util.Pair;
33
34import org.xmlpull.v1.XmlPullParser;
35import org.xmlpull.v1.XmlPullParserException;
36
37import android.content.BroadcastReceiver;
38import android.content.ComponentName;
39import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
42import android.content.IntentFilter;
43import android.content.IntentSender;
44import android.content.ServiceConnection;
45import android.content.SharedPreferences;
46import android.content.pm.ApplicationInfo;
47import android.content.pm.PackageManager;
48import android.content.res.AssetManager;
49import android.content.res.BridgeResources;
50import android.content.res.BridgeTypedArray;
51import android.content.res.Configuration;
52import android.content.res.Resources;
53import android.content.res.Resources.Theme;
54import android.content.res.TypedArray;
55import android.database.DatabaseErrorHandler;
56import android.database.sqlite.SQLiteDatabase;
57import android.database.sqlite.SQLiteDatabase.CursorFactory;
58import android.graphics.Bitmap;
59import android.graphics.drawable.Drawable;
60import android.net.Uri;
61import android.os.Bundle;
62import android.os.Handler;
63import android.os.Looper;
64import android.os.PowerManager;
65import android.os.UserHandle;
66import android.util.AttributeSet;
67import android.util.DisplayMetrics;
68import android.util.TypedValue;
69import android.view.BridgeInflater;
70import android.view.CompatibilityInfoHolder;
71import android.view.Display;
72import android.view.View;
73import android.view.ViewGroup;
74import android.view.WindowManager;
75import android.view.textservice.TextServicesManager;
76
77import java.io.File;
78import java.io.FileInputStream;
79import java.io.FileNotFoundException;
80import java.io.FileOutputStream;
81import java.io.IOException;
82import java.io.InputStream;
83import java.util.ArrayList;
84import java.util.HashMap;
85import java.util.IdentityHashMap;
86import java.util.List;
87import java.util.Map;
88
89/**
90 * Custom implementation of Context/Activity to handle non compiled resources.
91 */
92public final class BridgeContext extends Context {
93
94    private Resources mSystemResources;
95    private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
96    private final Object mProjectKey;
97    private final DisplayMetrics mMetrics;
98    private final RenderResources mRenderResources;
99    private final Configuration mConfig;
100    private final ApplicationInfo mApplicationInfo;
101    private final IProjectCallback mProjectCallback;
102    private final WindowManager mWindowManager;
103
104    private Resources.Theme mTheme;
105
106    private final Map<Object, Map<String, String>> mDefaultPropMaps =
107        new IdentityHashMap<Object, Map<String,String>>();
108
109    // maps for dynamically generated id representing style objects (StyleResourceValue)
110    private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
111    private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
112    private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
113
114    // cache for TypedArray generated from IStyleResourceValue object
115    private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
116    private BridgeInflater mBridgeInflater;
117
118    private BridgeContentResolver mContentResolver;
119
120    private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
121
122    /**
123     * @param projectKey An Object identifying the project. This is used for the cache mechanism.
124     * @param metrics the {@link DisplayMetrics}.
125     * @param renderResources the configured resources (both framework and projects) for this
126     * render.
127     * @param projectCallback
128     * @param config the Configuration object for this render.
129     * @param targetSdkVersion the targetSdkVersion of the application.
130     */
131    public BridgeContext(Object projectKey, DisplayMetrics metrics,
132            RenderResources renderResources,
133            IProjectCallback projectCallback,
134            Configuration config,
135            int targetSdkVersion) {
136        mProjectKey = projectKey;
137        mMetrics = metrics;
138        mProjectCallback = projectCallback;
139
140        mRenderResources = renderResources;
141        mConfig = config;
142
143        mApplicationInfo = new ApplicationInfo();
144        mApplicationInfo.targetSdkVersion = targetSdkVersion;
145
146        mWindowManager = new WindowManagerImpl(mMetrics);
147    }
148
149    /**
150     * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
151     * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}.
152     *
153     * @see #disposeResources()
154     */
155    public void initResources() {
156        AssetManager assetManager = AssetManager.getSystem();
157
158        mSystemResources = BridgeResources.initSystem(
159                this,
160                assetManager,
161                mMetrics,
162                mConfig,
163                mProjectCallback);
164        mTheme = mSystemResources.newTheme();
165    }
166
167    /**
168     * Disposes the {@link Resources} singleton.
169     */
170    public void disposeResources() {
171        BridgeResources.disposeSystem();
172    }
173
174    public void setBridgeInflater(BridgeInflater inflater) {
175        mBridgeInflater = inflater;
176    }
177
178    public void addViewKey(View view, Object viewKey) {
179        mViewKeyMap.put(view, viewKey);
180    }
181
182    public Object getViewKey(View view) {
183        return mViewKeyMap.get(view);
184    }
185
186    public Object getProjectKey() {
187        return mProjectKey;
188    }
189
190    public DisplayMetrics getMetrics() {
191        return mMetrics;
192    }
193
194    public IProjectCallback getProjectCallback() {
195        return mProjectCallback;
196    }
197
198    public RenderResources getRenderResources() {
199        return mRenderResources;
200    }
201
202    public Map<String, String> getDefaultPropMap(Object key) {
203        return mDefaultPropMaps.get(key);
204    }
205
206    public Configuration getConfiguration() {
207        return mConfig;
208    }
209
210    /**
211     * Adds a parser to the stack.
212     * @param parser the parser to add.
213     */
214    public void pushParser(BridgeXmlBlockParser parser) {
215        if (ParserFactory.LOG_PARSER) {
216            System.out.println("PUSH " + parser.getParser().toString());
217        }
218        mParserStack.push(parser);
219    }
220
221    /**
222     * Removes the parser at the top of the stack
223     */
224    public void popParser() {
225        BridgeXmlBlockParser parser = mParserStack.pop();
226        if (ParserFactory.LOG_PARSER) {
227            System.out.println("POPD " + parser.getParser().toString());
228        }
229    }
230
231    /**
232     * Returns the current parser at the top the of the stack.
233     * @return a parser or null.
234     */
235    public BridgeXmlBlockParser getCurrentParser() {
236        return mParserStack.peek();
237    }
238
239    /**
240     * Returns the previous parser.
241     * @return a parser or null if there isn't any previous parser
242     */
243    public BridgeXmlBlockParser getPreviousParser() {
244        if (mParserStack.size() < 2) {
245            return null;
246        }
247        return mParserStack.get(mParserStack.size() - 2);
248    }
249
250    public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
251        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
252        boolean isFrameworkRes = true;
253        if (resourceInfo == null) {
254            resourceInfo = mProjectCallback.resolveResourceId(resid);
255            isFrameworkRes = false;
256        }
257
258        if (resourceInfo == null) {
259            return false;
260        }
261
262        ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(),
263                isFrameworkRes);
264        if (resolveRefs) {
265            value = mRenderResources.resolveResValue(value);
266        }
267
268        // check if this is a style resource
269        if (value instanceof StyleResourceValue) {
270            // get the id that will represent this style.
271            outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value);
272            return true;
273        }
274
275
276        int a;
277        // if this is a framework value.
278        if (value.isFramework()) {
279            // look for idName in the android R classes.
280            // use 0 a default res value as it's not a valid id value.
281            a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
282        } else {
283            // look for idName in the project R class.
284            // use 0 a default res value as it's not a valid id value.
285            a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
286        }
287
288        if (a != 0) {
289            outValue.resourceId = a;
290            return true;
291        }
292
293        return false;
294    }
295
296
297    public ResourceReference resolveId(int id) {
298        // first get the String related to this id in the framework
299        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
300
301        if (resourceInfo != null) {
302            return new ResourceReference(resourceInfo.getSecond(), true);
303        }
304
305        // didn't find a match in the framework? look in the project.
306        if (mProjectCallback != null) {
307            resourceInfo = mProjectCallback.resolveResourceId(id);
308
309            if (resourceInfo != null) {
310                return new ResourceReference(resourceInfo.getSecond(), false);
311            }
312        }
313
314        return null;
315    }
316
317    public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
318            boolean attachToRoot, boolean skipCallbackParser) {
319        boolean isPlatformLayout = resource.isFramework();
320
321        if (isPlatformLayout == false && skipCallbackParser == false) {
322            // check if the project callback can provide us with a custom parser.
323            ILayoutPullParser parser = getParser(resource);
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    @SuppressWarnings("deprecation")
397    private ILayoutPullParser getParser(ResourceReference resource) {
398        ILayoutPullParser parser;
399        if (resource instanceof ResourceValue) {
400            parser = mProjectCallback.getParser((ResourceValue) resource);
401        } else {
402            parser = mProjectCallback.getParser(resource.getName());
403        }
404        return parser;
405    }
406
407    // ------------ Context methods
408
409    @Override
410    public Resources getResources() {
411        return mSystemResources;
412    }
413
414    @Override
415    public Theme getTheme() {
416        return mTheme;
417    }
418
419    @Override
420    public ClassLoader getClassLoader() {
421        return this.getClass().getClassLoader();
422    }
423
424    @Override
425    public Object getSystemService(String service) {
426        if (LAYOUT_INFLATER_SERVICE.equals(service)) {
427            return mBridgeInflater;
428        }
429
430        if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) {
431            // we need to return a valid service to avoid NPE
432            return TextServicesManager.getInstance();
433        }
434
435        if (WINDOW_SERVICE.equals(service)) {
436            return mWindowManager;
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 createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
923        // pass
924        return null;
925    }
926
927    @Override
928    public Context createConfigurationContext(Configuration overrideConfiguration) {
929        // pass
930        return null;
931    }
932
933    @Override
934    public Context createDisplayContext(Display display) {
935        // pass
936        return null;
937    }
938
939    @Override
940    public String[] databaseList() {
941        // pass
942        return null;
943    }
944
945    @Override
946    public boolean deleteDatabase(String arg0) {
947        // pass
948        return false;
949    }
950
951    @Override
952    public boolean deleteFile(String arg0) {
953        // pass
954        return false;
955    }
956
957    @Override
958    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
959        // pass
960
961    }
962
963    @Override
964    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
965            String arg2) {
966        // pass
967
968    }
969
970    @Override
971    public void enforceCallingPermission(String arg0, String arg1) {
972        // pass
973
974    }
975
976    @Override
977    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
978        // pass
979
980    }
981
982    @Override
983    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
984        // pass
985
986    }
987
988    @Override
989    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
990            String arg4) {
991        // pass
992
993    }
994
995    @Override
996    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
997            int arg3, int arg4, int arg5, String arg6) {
998        // pass
999
1000    }
1001
1002    @Override
1003    public String[] fileList() {
1004        // pass
1005        return null;
1006    }
1007
1008    @Override
1009    public AssetManager getAssets() {
1010        // pass
1011        return null;
1012    }
1013
1014    @Override
1015    public File getCacheDir() {
1016        // pass
1017        return null;
1018    }
1019
1020    @Override
1021    public File getExternalCacheDir() {
1022        // pass
1023        return null;
1024    }
1025
1026    @Override
1027    public ContentResolver getContentResolver() {
1028        if (mContentResolver == null) {
1029            mContentResolver = new BridgeContentResolver(this);
1030        }
1031        return mContentResolver;
1032    }
1033
1034    @Override
1035    public File getDatabasePath(String arg0) {
1036        // pass
1037        return null;
1038    }
1039
1040    @Override
1041    public File getDir(String arg0, int arg1) {
1042        // pass
1043        return null;
1044    }
1045
1046    @Override
1047    public File getFileStreamPath(String arg0) {
1048        // pass
1049        return null;
1050    }
1051
1052    @Override
1053    public File getFilesDir() {
1054        // pass
1055        return null;
1056    }
1057
1058    @Override
1059    public File getExternalFilesDir(String type) {
1060        // pass
1061        return null;
1062    }
1063
1064    @Override
1065    public String getPackageCodePath() {
1066        // pass
1067        return null;
1068    }
1069
1070    @Override
1071    public PackageManager getPackageManager() {
1072        // pass
1073        return null;
1074    }
1075
1076    @Override
1077    public String getPackageName() {
1078        // pass
1079        return null;
1080    }
1081
1082    @Override
1083    public ApplicationInfo getApplicationInfo() {
1084        return mApplicationInfo;
1085    }
1086
1087    @Override
1088    public String getPackageResourcePath() {
1089        // pass
1090        return null;
1091    }
1092
1093    @Override
1094    public File getSharedPrefsFile(String name) {
1095        // pass
1096        return null;
1097    }
1098
1099    @Override
1100    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1101        // pass
1102        return null;
1103    }
1104
1105    @Override
1106    public Drawable getWallpaper() {
1107        // pass
1108        return null;
1109    }
1110
1111    @Override
1112    public int getWallpaperDesiredMinimumWidth() {
1113        return -1;
1114    }
1115
1116    @Override
1117    public int getWallpaperDesiredMinimumHeight() {
1118        return -1;
1119    }
1120
1121    @Override
1122    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1123        // pass
1124
1125    }
1126
1127    @Override
1128    public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1129        // pass
1130        return null;
1131    }
1132
1133    @Override
1134    public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1135        // pass
1136        return null;
1137    }
1138
1139    @Override
1140    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1141        // pass
1142        return null;
1143    }
1144
1145    @Override
1146    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1147            CursorFactory arg2, DatabaseErrorHandler arg3) {
1148        // pass
1149        return null;
1150    }
1151
1152    @Override
1153    public Drawable peekWallpaper() {
1154        // pass
1155        return null;
1156    }
1157
1158    @Override
1159    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1160        // pass
1161        return null;
1162    }
1163
1164    @Override
1165    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1166            String arg2, Handler arg3) {
1167        // pass
1168        return null;
1169    }
1170
1171    @Override
1172    public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
1173            IntentFilter arg1, String arg2, Handler arg3) {
1174        // pass
1175        return null;
1176    }
1177
1178    @Override
1179    public void removeStickyBroadcast(Intent arg0) {
1180        // pass
1181
1182    }
1183
1184    @Override
1185    public void revokeUriPermission(Uri arg0, int arg1) {
1186        // pass
1187
1188    }
1189
1190    @Override
1191    public void sendBroadcast(Intent arg0) {
1192        // pass
1193
1194    }
1195
1196    @Override
1197    public void sendBroadcast(Intent arg0, String arg1) {
1198        // pass
1199
1200    }
1201
1202    @Override
1203    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1204        // pass
1205
1206    }
1207
1208    @Override
1209    public void sendOrderedBroadcast(Intent arg0, String arg1,
1210            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1211            Bundle arg6) {
1212        // pass
1213
1214    }
1215
1216    @Override
1217    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
1218        // pass
1219    }
1220
1221    @Override
1222    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1223            String receiverPermission) {
1224        // pass
1225    }
1226
1227    @Override
1228    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1229            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
1230            int initialCode, String initialData, Bundle initialExtras) {
1231        // pass
1232    }
1233
1234    @Override
1235    public void sendStickyBroadcast(Intent arg0) {
1236        // pass
1237
1238    }
1239
1240    @Override
1241    public void sendStickyOrderedBroadcast(Intent intent,
1242            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1243           Bundle initialExtras) {
1244        // pass
1245    }
1246
1247    @Override
1248    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
1249        // pass
1250    }
1251
1252    @Override
1253    public void sendStickyOrderedBroadcastAsUser(Intent intent,
1254            UserHandle user, BroadcastReceiver resultReceiver,
1255            Handler scheduler, int initialCode, String initialData,
1256            Bundle initialExtras) {
1257        // pass
1258    }
1259
1260    @Override
1261    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
1262        // pass
1263    }
1264
1265    @Override
1266    public void setTheme(int arg0) {
1267        // pass
1268
1269    }
1270
1271    @Override
1272    public void setWallpaper(Bitmap arg0) throws IOException {
1273        // pass
1274
1275    }
1276
1277    @Override
1278    public void setWallpaper(InputStream arg0) throws IOException {
1279        // pass
1280
1281    }
1282
1283    @Override
1284    public void startActivity(Intent arg0) {
1285        // pass
1286    }
1287
1288    @Override
1289    public void startActivity(Intent arg0, Bundle arg1) {
1290        // pass
1291    }
1292
1293    @Override
1294    public void startIntentSender(IntentSender intent,
1295            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1296            throws IntentSender.SendIntentException {
1297        // pass
1298    }
1299
1300    @Override
1301    public void startIntentSender(IntentSender intent,
1302            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1303            Bundle options) throws IntentSender.SendIntentException {
1304        // pass
1305    }
1306
1307    @Override
1308    public boolean startInstrumentation(ComponentName arg0, String arg1,
1309            Bundle arg2) {
1310        // pass
1311        return false;
1312    }
1313
1314    @Override
1315    public ComponentName startService(Intent arg0) {
1316        // pass
1317        return null;
1318    }
1319
1320    @Override
1321    public boolean stopService(Intent arg0) {
1322        // pass
1323        return false;
1324    }
1325
1326    @Override
1327    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
1328        // pass
1329        return null;
1330    }
1331
1332    @Override
1333    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
1334        // pass
1335        return false;
1336    }
1337
1338    @Override
1339    public void unbindService(ServiceConnection arg0) {
1340        // pass
1341
1342    }
1343
1344    @Override
1345    public void unregisterReceiver(BroadcastReceiver arg0) {
1346        // pass
1347
1348    }
1349
1350    @Override
1351    public Context getApplicationContext() {
1352        return this;
1353    }
1354
1355    @Override
1356    public void startActivities(Intent[] arg0) {
1357        // pass
1358
1359    }
1360
1361    @Override
1362    public void startActivities(Intent[] arg0, Bundle arg1) {
1363        // pass
1364
1365    }
1366
1367    @Override
1368    public boolean isRestricted() {
1369        return false;
1370    }
1371
1372    @Override
1373    public File getObbDir() {
1374        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1375        return null;
1376    }
1377
1378    @Override
1379    public CompatibilityInfoHolder getCompatibilityInfo(int displayId) {
1380        // pass
1381        return null;
1382    }
1383}
1384