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