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