BridgeContext.java revision 4ccc4bd54f85d86818f61d728c6361d2003ddd8e
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.Display;
71import android.view.DisplayAdjustments;
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                        || (value.getFirst() == ResourceType.ATTR)) {
609                    // look for the style in the current theme, and its parent:
610                    ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(),
611                            isFrameworkRes);
612                    if (item != null) {
613                        if (item instanceof StyleResourceValue) {
614                            if (defaultPropMap != null) {
615                                defaultPropMap.put("style", item.getName());
616                            }
617
618                            defStyleValues = (StyleResourceValue)item;
619                        }
620                    } else {
621                        Bridge.getLog().error(null,
622                                String.format(
623                                        "Style with id 0x%x (resolved to '%s') does not exist.",
624                                        defStyleRes, value.getSecond()),
625                                null /*data*/);
626                    }
627                } else {
628                    Bridge.getLog().error(null,
629                            String.format(
630                                    "Resouce id 0x%x is not of type STYLE (instead %s)",
631                                    defStyleRes, value.getFirst().toString()),
632                            null /*data*/);
633                }
634            } else {
635                Bridge.getLog().error(null,
636                        String.format(
637                                "Failed to find style with id 0x%x in current theme",
638                                defStyleRes),
639                        null /*data*/);
640            }
641        }
642
643        String appNamespace = mProjectCallback.getNamespace();
644
645        if (attributeList != null) {
646            for (int index = 0 ; index < attributeList.size() ; index++) {
647                Pair<String, Boolean> attribute = attributeList.get(index);
648
649                if (attribute == null) {
650                    continue;
651                }
652
653                String attrName = attribute.getFirst();
654                boolean frameworkAttr = attribute.getSecond().booleanValue();
655                String value = null;
656                if (set != null) {
657                    value = set.getAttributeValue(
658                            frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace,
659                                    attrName);
660
661                    // if this is an app attribute, and the first get fails, try with the
662                    // new res-auto namespace as well
663                    if (frameworkAttr == false && value == null) {
664                        value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
665                    }
666                }
667
668                // if there's no direct value for this attribute in the XML, we look for default
669                // values in the widget defStyle, and then in the theme.
670                if (value == null) {
671                    ResourceValue resValue = null;
672
673                    // look for the value in the custom style first (and its parent if needed)
674                    if (customStyleValues != null) {
675                        resValue = mRenderResources.findItemInStyle(customStyleValues,
676                                attrName, frameworkAttr);
677                    }
678
679                    // then look for the value in the default Style (and its parent if needed)
680                    if (resValue == null && defStyleValues != null) {
681                        resValue = mRenderResources.findItemInStyle(defStyleValues,
682                                attrName, frameworkAttr);
683                    }
684
685                    // if the item is not present in the defStyle, we look in the main theme (and
686                    // its parent themes)
687                    if (resValue == null) {
688                        resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
689                    }
690
691                    // if we found a value, we make sure this doesn't reference another value.
692                    // So we resolve it.
693                    if (resValue != null) {
694                        // put the first default value, before the resolution.
695                        if (defaultPropMap != null) {
696                            defaultPropMap.put(attrName, resValue.getValue());
697                        }
698
699                        resValue = mRenderResources.resolveResValue(resValue);
700                    }
701
702                    ta.bridgeSetValue(index, attrName, frameworkAttr, resValue);
703                } else {
704                    // there is a value in the XML, but we need to resolve it in case it's
705                    // referencing another resource or a theme value.
706                    ta.bridgeSetValue(index, attrName, frameworkAttr,
707                            mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
708                }
709            }
710        }
711
712        ta.sealArray();
713
714        return ta;
715    }
716
717    @Override
718    public Looper getMainLooper() {
719        return Looper.myLooper();
720    }
721
722
723    // ------------- private new methods
724
725    /**
726     * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
727     * values found in the given style.
728     * @see #obtainStyledAttributes(int, int[])
729     */
730    private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
731            throws Resources.NotFoundException {
732
733        List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
734
735        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
736                false);
737
738        // for each attribute, get its name so that we can search it in the style
739        for (int i = 0 ; i < attrs.length ; i++) {
740            Pair<String, Boolean> attribute = attributes.get(i);
741
742            if (attribute != null) {
743                // look for the value in the given style
744                ResourceValue resValue = mRenderResources.findItemInStyle(style,
745                        attribute.getFirst(), attribute.getSecond());
746
747                if (resValue != null) {
748                    // resolve it to make sure there are no references left.
749                    ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(),
750                            mRenderResources.resolveResValue(resValue));
751                }
752            }
753        }
754
755        ta.sealArray();
756
757        return ta;
758    }
759
760
761    /**
762     * The input int[] attrs is a list of attributes. The returns a list of information about
763     * each attributes. The information is (name, isFramework)
764     * <p/>
765     *
766     * @param attrs An attribute array reference given to obtainStyledAttributes.
767     * @return List of attribute information.
768     */
769    private List<Pair<String, Boolean>> searchAttrs(int[] attrs) {
770        List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length);
771
772        // for each attribute, get its name so that we can search it in the style
773        for (int i = 0 ; i < attrs.length ; i++) {
774            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
775            boolean isFramework = false;
776            if (resolvedResource != null) {
777                isFramework = true;
778            } else {
779                resolvedResource = mProjectCallback.resolveResourceId(attrs[i]);
780            }
781
782            if (resolvedResource != null) {
783                results.add(Pair.of(resolvedResource.getSecond(), isFramework));
784            } else {
785                results.add(null);
786            }
787        }
788
789        return results;
790    }
791
792    /**
793     * Searches for the attribute referenced by its internal id.
794     *
795     * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
796     * @return A (name, isFramework) pair describing the attribute if found. Returns null
797     *         if nothing is found.
798     */
799    public Pair<String, Boolean> searchAttr(int attr) {
800        Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
801        if (info != null) {
802            return Pair.of(info.getSecond(), Boolean.TRUE);
803        }
804
805        info = mProjectCallback.resolveResourceId(attr);
806        if (info != null) {
807            return Pair.of(info.getSecond(), Boolean.FALSE);
808        }
809
810        return null;
811    }
812
813    public int getDynamicIdByStyle(StyleResourceValue resValue) {
814        if (mDynamicIdToStyleMap == null) {
815            // create the maps.
816            mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
817            mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
818        }
819
820        // look for an existing id
821        Integer id = mStyleToDynamicIdMap.get(resValue);
822
823        if (id == null) {
824            // generate a new id
825            id = Integer.valueOf(++mDynamicIdGenerator);
826
827            // and add it to the maps.
828            mDynamicIdToStyleMap.put(id, resValue);
829            mStyleToDynamicIdMap.put(resValue, id);
830        }
831
832        return id;
833    }
834
835    private StyleResourceValue getStyleByDynamicId(int i) {
836        if (mDynamicIdToStyleMap != null) {
837            return mDynamicIdToStyleMap.get(i);
838        }
839
840        return null;
841    }
842
843    public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
844        Integer value = Bridge.getResourceId(resType, resName);
845        if (value != null) {
846            return value.intValue();
847        }
848
849        return defValue;
850    }
851
852    public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
853        if (mProjectCallback != null) {
854            Integer value = mProjectCallback.getResourceId(resType, resName);
855            if (value != null) {
856                return value.intValue();
857            }
858        }
859
860        return defValue;
861    }
862
863    //------------ NOT OVERRIDEN --------------------
864
865    @Override
866    public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
867        // pass
868        return false;
869    }
870
871    @Override
872    public int checkCallingOrSelfPermission(String arg0) {
873        // pass
874        return 0;
875    }
876
877    @Override
878    public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
879        // pass
880        return 0;
881    }
882
883    @Override
884    public int checkCallingPermission(String arg0) {
885        // pass
886        return 0;
887    }
888
889    @Override
890    public int checkCallingUriPermission(Uri arg0, int arg1) {
891        // pass
892        return 0;
893    }
894
895    @Override
896    public int checkPermission(String arg0, int arg1, int arg2) {
897        // pass
898        return 0;
899    }
900
901    @Override
902    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
903        // pass
904        return 0;
905    }
906
907    @Override
908    public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
909            int arg4, int arg5) {
910        // pass
911        return 0;
912    }
913
914    @Override
915    public void clearWallpaper() {
916        // pass
917
918    }
919
920    @Override
921    public Context createPackageContext(String arg0, int arg1) {
922        // pass
923        return null;
924    }
925
926    @Override
927    public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
928        // pass
929        return null;
930    }
931
932    @Override
933    public Context createConfigurationContext(Configuration overrideConfiguration) {
934        // pass
935        return null;
936    }
937
938    @Override
939    public Context createDisplayContext(Display display) {
940        // pass
941        return null;
942    }
943
944    @Override
945    public String[] databaseList() {
946        // pass
947        return null;
948    }
949
950    @Override
951    public boolean deleteDatabase(String arg0) {
952        // pass
953        return false;
954    }
955
956    @Override
957    public boolean deleteFile(String arg0) {
958        // pass
959        return false;
960    }
961
962    @Override
963    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
964        // pass
965
966    }
967
968    @Override
969    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
970            String arg2) {
971        // pass
972
973    }
974
975    @Override
976    public void enforceCallingPermission(String arg0, String arg1) {
977        // pass
978
979    }
980
981    @Override
982    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
983        // pass
984
985    }
986
987    @Override
988    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
989        // pass
990
991    }
992
993    @Override
994    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
995            String arg4) {
996        // pass
997
998    }
999
1000    @Override
1001    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
1002            int arg3, int arg4, int arg5, String arg6) {
1003        // pass
1004
1005    }
1006
1007    @Override
1008    public String[] fileList() {
1009        // pass
1010        return null;
1011    }
1012
1013    @Override
1014    public AssetManager getAssets() {
1015        // pass
1016        return null;
1017    }
1018
1019    @Override
1020    public File getCacheDir() {
1021        // pass
1022        return null;
1023    }
1024
1025    @Override
1026    public File getExternalCacheDir() {
1027        // pass
1028        return null;
1029    }
1030
1031    @Override
1032    public ContentResolver getContentResolver() {
1033        if (mContentResolver == null) {
1034            mContentResolver = new BridgeContentResolver(this);
1035        }
1036        return mContentResolver;
1037    }
1038
1039    @Override
1040    public File getDatabasePath(String arg0) {
1041        // pass
1042        return null;
1043    }
1044
1045    @Override
1046    public File getDir(String arg0, int arg1) {
1047        // pass
1048        return null;
1049    }
1050
1051    @Override
1052    public File getFileStreamPath(String arg0) {
1053        // pass
1054        return null;
1055    }
1056
1057    @Override
1058    public File getFilesDir() {
1059        // pass
1060        return null;
1061    }
1062
1063    @Override
1064    public File getExternalFilesDir(String type) {
1065        // pass
1066        return null;
1067    }
1068
1069    @Override
1070    public String getPackageCodePath() {
1071        // pass
1072        return null;
1073    }
1074
1075    @Override
1076    public PackageManager getPackageManager() {
1077        // pass
1078        return null;
1079    }
1080
1081    @Override
1082    public String getPackageName() {
1083        // pass
1084        return null;
1085    }
1086
1087    @Override
1088    public String getBasePackageName() {
1089        // pass
1090        return null;
1091    }
1092
1093    @Override
1094    public String getOpPackageName() {
1095        // pass
1096        return null;
1097    }
1098
1099    @Override
1100    public ApplicationInfo getApplicationInfo() {
1101        return mApplicationInfo;
1102    }
1103
1104    @Override
1105    public String getPackageResourcePath() {
1106        // pass
1107        return null;
1108    }
1109
1110    @Override
1111    public File getSharedPrefsFile(String name) {
1112        // pass
1113        return null;
1114    }
1115
1116    @Override
1117    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1118        // pass
1119        return null;
1120    }
1121
1122    @Override
1123    public Drawable getWallpaper() {
1124        // pass
1125        return null;
1126    }
1127
1128    @Override
1129    public int getWallpaperDesiredMinimumWidth() {
1130        return -1;
1131    }
1132
1133    @Override
1134    public int getWallpaperDesiredMinimumHeight() {
1135        return -1;
1136    }
1137
1138    @Override
1139    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1140        // pass
1141
1142    }
1143
1144    @Override
1145    public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1146        // pass
1147        return null;
1148    }
1149
1150    @Override
1151    public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1152        // pass
1153        return null;
1154    }
1155
1156    @Override
1157    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1158        // pass
1159        return null;
1160    }
1161
1162    @Override
1163    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1164            CursorFactory arg2, DatabaseErrorHandler arg3) {
1165        // pass
1166        return null;
1167    }
1168
1169    @Override
1170    public Drawable peekWallpaper() {
1171        // pass
1172        return null;
1173    }
1174
1175    @Override
1176    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1177        // pass
1178        return null;
1179    }
1180
1181    @Override
1182    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1183            String arg2, Handler arg3) {
1184        // pass
1185        return null;
1186    }
1187
1188    @Override
1189    public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
1190            IntentFilter arg1, String arg2, Handler arg3) {
1191        // pass
1192        return null;
1193    }
1194
1195    @Override
1196    public void removeStickyBroadcast(Intent arg0) {
1197        // pass
1198
1199    }
1200
1201    @Override
1202    public void revokeUriPermission(Uri arg0, int arg1) {
1203        // pass
1204
1205    }
1206
1207    @Override
1208    public void sendBroadcast(Intent arg0) {
1209        // pass
1210
1211    }
1212
1213    @Override
1214    public void sendBroadcast(Intent arg0, String arg1) {
1215        // pass
1216
1217    }
1218
1219    @Override
1220    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
1221        // pass
1222    }
1223
1224    @Override
1225    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1226        // pass
1227
1228    }
1229
1230    @Override
1231    public void sendOrderedBroadcast(Intent arg0, String arg1,
1232            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1233            Bundle arg6) {
1234        // pass
1235
1236    }
1237
1238    @Override
1239    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
1240            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
1241            String initialData, Bundle initialExtras) {
1242        // pass
1243    }
1244
1245    @Override
1246    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
1247        // pass
1248    }
1249
1250    @Override
1251    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1252            String receiverPermission) {
1253        // pass
1254    }
1255
1256    @Override
1257    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1258            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
1259            int initialCode, String initialData, Bundle initialExtras) {
1260        // pass
1261    }
1262
1263    @Override
1264    public void sendStickyBroadcast(Intent arg0) {
1265        // pass
1266
1267    }
1268
1269    @Override
1270    public void sendStickyOrderedBroadcast(Intent intent,
1271            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1272           Bundle initialExtras) {
1273        // pass
1274    }
1275
1276    @Override
1277    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
1278        // pass
1279    }
1280
1281    @Override
1282    public void sendStickyOrderedBroadcastAsUser(Intent intent,
1283            UserHandle user, BroadcastReceiver resultReceiver,
1284            Handler scheduler, int initialCode, String initialData,
1285            Bundle initialExtras) {
1286        // pass
1287    }
1288
1289    @Override
1290    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
1291        // pass
1292    }
1293
1294    @Override
1295    public void setTheme(int arg0) {
1296        // pass
1297
1298    }
1299
1300    @Override
1301    public void setWallpaper(Bitmap arg0) throws IOException {
1302        // pass
1303
1304    }
1305
1306    @Override
1307    public void setWallpaper(InputStream arg0) throws IOException {
1308        // pass
1309
1310    }
1311
1312    @Override
1313    public void startActivity(Intent arg0) {
1314        // pass
1315    }
1316
1317    @Override
1318    public void startActivity(Intent arg0, Bundle arg1) {
1319        // pass
1320    }
1321
1322    @Override
1323    public void startIntentSender(IntentSender intent,
1324            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1325            throws IntentSender.SendIntentException {
1326        // pass
1327    }
1328
1329    @Override
1330    public void startIntentSender(IntentSender intent,
1331            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1332            Bundle options) throws IntentSender.SendIntentException {
1333        // pass
1334    }
1335
1336    @Override
1337    public boolean startInstrumentation(ComponentName arg0, String arg1,
1338            Bundle arg2) {
1339        // pass
1340        return false;
1341    }
1342
1343    @Override
1344    public ComponentName startService(Intent arg0) {
1345        // pass
1346        return null;
1347    }
1348
1349    @Override
1350    public boolean stopService(Intent arg0) {
1351        // pass
1352        return false;
1353    }
1354
1355    @Override
1356    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
1357        // pass
1358        return null;
1359    }
1360
1361    @Override
1362    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
1363        // pass
1364        return false;
1365    }
1366
1367    @Override
1368    public void unbindService(ServiceConnection arg0) {
1369        // pass
1370
1371    }
1372
1373    @Override
1374    public void unregisterReceiver(BroadcastReceiver arg0) {
1375        // pass
1376
1377    }
1378
1379    @Override
1380    public Context getApplicationContext() {
1381        return this;
1382    }
1383
1384    @Override
1385    public void startActivities(Intent[] arg0) {
1386        // pass
1387
1388    }
1389
1390    @Override
1391    public void startActivities(Intent[] arg0, Bundle arg1) {
1392        // pass
1393
1394    }
1395
1396    @Override
1397    public boolean isRestricted() {
1398        return false;
1399    }
1400
1401    @Override
1402    public File getObbDir() {
1403        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1404        return null;
1405    }
1406
1407    @Override
1408    public DisplayAdjustments getDisplayAdjustments(int displayId) {
1409        // pass
1410        return null;
1411    }
1412
1413    /**
1414     * @hide
1415     */
1416    @Override
1417    public int getUserId() {
1418        return 0; // not used
1419    }
1420
1421    @Override
1422    public File[] getExternalFilesDirs(String type) {
1423        // pass
1424        return new File[0];
1425    }
1426
1427    @Override
1428    public File[] getObbDirs() {
1429        // pass
1430        return new File[0];
1431    }
1432
1433    @Override
1434    public File[] getExternalCacheDirs() {
1435        // pass
1436        return new File[0];
1437    }
1438}
1439