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