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