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