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