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