BridgeContext.java revision 040f7446638281d80a7c6ca2b25f73b59dcef421
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
142  /**
143     * @param projectKey An Object identifying the project. This is used for the cache mechanism.
144     * @param metrics the {@link DisplayMetrics}.
145     * @param renderResources the configured resources (both framework and projects) for this
146     * render.
147     * @param config the Configuration object for this render.
148     * @param targetSdkVersion the targetSdkVersion of the application.
149     */
150    public BridgeContext(Object projectKey, DisplayMetrics metrics,
151            RenderResources renderResources,
152            AssetRepository assets,
153            LayoutlibCallback layoutlibCallback,
154            Configuration config,
155            int targetSdkVersion,
156            boolean hasRtlSupport) {
157        mProjectKey = projectKey;
158        mMetrics = metrics;
159        mLayoutlibCallback = layoutlibCallback;
160
161        mRenderResources = renderResources;
162        mConfig = config;
163        mAssets = new BridgeAssetManager();
164        mAssets.setAssetRepository(assets);
165
166        mApplicationInfo = new ApplicationInfo();
167        mApplicationInfo.targetSdkVersion = targetSdkVersion;
168        if (hasRtlSupport) {
169            mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
170        }
171
172        mWindowManager = new WindowManagerImpl(mMetrics);
173        mDisplayManager = new DisplayManager(this);
174    }
175
176    /**
177     * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
178     * {@link DisplayMetrics}, {@link Configuration}, and {@link LayoutlibCallback}.
179     *
180     * @see #disposeResources()
181     */
182    public void initResources() {
183        AssetManager assetManager = AssetManager.getSystem();
184
185        mSystemResources = BridgeResources.initSystem(
186                this,
187                assetManager,
188                mMetrics,
189                mConfig,
190                mLayoutlibCallback);
191        mTheme = mSystemResources.newTheme();
192    }
193
194    /**
195     * Disposes the {@link Resources} singleton.
196     */
197    public void disposeResources() {
198        BridgeResources.disposeSystem();
199    }
200
201    public void setBridgeInflater(BridgeInflater inflater) {
202        mBridgeInflater = inflater;
203    }
204
205    public void addViewKey(View view, Object viewKey) {
206        mViewKeyMap.put(view, viewKey);
207    }
208
209    public Object getViewKey(View view) {
210        return mViewKeyMap.get(view);
211    }
212
213    public void addCookie(Object o, Object cookie) {
214        mViewKeyHelpMap.put(o, cookie);
215    }
216
217    public Object getCookie(Object o) {
218        return mViewKeyHelpMap.get(o);
219    }
220
221    public Object getProjectKey() {
222        return mProjectKey;
223    }
224
225    public DisplayMetrics getMetrics() {
226        return mMetrics;
227    }
228
229    public LayoutlibCallback getLayoutlibCallback() {
230        return mLayoutlibCallback;
231    }
232
233    public RenderResources getRenderResources() {
234        return mRenderResources;
235    }
236
237    public Map<String, String> getDefaultPropMap(Object key) {
238        return mDefaultPropMaps.get(key);
239    }
240
241    public Configuration getConfiguration() {
242        return mConfig;
243    }
244
245    /**
246     * Adds a parser to the stack.
247     * @param parser the parser to add.
248     */
249    public void pushParser(BridgeXmlBlockParser parser) {
250        if (ParserFactory.LOG_PARSER) {
251            System.out.println("PUSH " + parser.getParser().toString());
252        }
253        mParserStack.push(parser);
254    }
255
256    /**
257     * Removes the parser at the top of the stack
258     */
259    public void popParser() {
260        BridgeXmlBlockParser parser = mParserStack.pop();
261        if (ParserFactory.LOG_PARSER) {
262            System.out.println("POPD " + parser.getParser().toString());
263        }
264    }
265
266    /**
267     * Returns the current parser at the top the of the stack.
268     * @return a parser or null.
269     */
270    public BridgeXmlBlockParser getCurrentParser() {
271        return mParserStack.peek();
272    }
273
274    /**
275     * Returns the previous parser.
276     * @return a parser or null if there isn't any previous parser
277     */
278    public BridgeXmlBlockParser getPreviousParser() {
279        if (mParserStack.size() < 2) {
280            return null;
281        }
282        return mParserStack.get(mParserStack.size() - 2);
283    }
284
285    public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
286        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
287        boolean isFrameworkRes = true;
288        if (resourceInfo == null) {
289            resourceInfo = mLayoutlibCallback.resolveResourceId(resid);
290            isFrameworkRes = false;
291        }
292
293        if (resourceInfo == null) {
294            return false;
295        }
296
297        ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(),
298                isFrameworkRes);
299        if (resolveRefs) {
300            value = mRenderResources.resolveResValue(value);
301        }
302
303        if (value == null) {
304            // unable to find the attribute.
305            return false;
306        }
307
308        // check if this is a style resource
309        if (value instanceof StyleResourceValue) {
310            // get the id that will represent this style.
311            outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value);
312            return true;
313        }
314
315        int a;
316        // if this is a framework value.
317        if (value.isFramework()) {
318            // look for idName in the android R classes.
319            // use 0 a default res value as it's not a valid id value.
320            a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
321        } else {
322            // look for idName in the project R class.
323            // use 0 a default res value as it's not a valid id value.
324            a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
325        }
326
327        if (a != 0) {
328            outValue.resourceId = a;
329            return true;
330        }
331
332        return false;
333    }
334
335
336    public ResourceReference resolveId(int id) {
337        // first get the String related to this id in the framework
338        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
339
340        if (resourceInfo != null) {
341            return new ResourceReference(resourceInfo.getSecond(), true);
342        }
343
344        // didn't find a match in the framework? look in the project.
345        if (mLayoutlibCallback != null) {
346            resourceInfo = mLayoutlibCallback.resolveResourceId(id);
347
348            if (resourceInfo != null) {
349                return new ResourceReference(resourceInfo.getSecond(), false);
350            }
351        }
352
353        // The base value for R.style is 0x01030000 and the custom style is 0x02030000.
354        // So, if the second byte is 03, it's probably a style.
355        if ((id >> 16 & 0xFF) == 0x03) {
356            return getStyleByDynamicId(id);
357        }
358        return null;
359    }
360
361    public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
362            boolean attachToRoot, boolean skipCallbackParser) {
363        boolean isPlatformLayout = resource.isFramework();
364
365        if (!isPlatformLayout && !skipCallbackParser) {
366            // check if the project callback can provide us with a custom parser.
367            ILayoutPullParser parser = getParser(resource);
368
369            if (parser != null) {
370                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
371                        this, resource.isFramework());
372                try {
373                    pushParser(blockParser);
374                    return Pair.of(
375                            mBridgeInflater.inflate(blockParser, parent, attachToRoot),
376                            true);
377                } finally {
378                    popParser();
379                }
380            }
381        }
382
383        ResourceValue resValue;
384        if (resource instanceof ResourceValue) {
385            resValue = (ResourceValue) resource;
386        } else {
387            if (isPlatformLayout) {
388                resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT,
389                        resource.getName());
390            } else {
391                resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT,
392                        resource.getName());
393            }
394        }
395
396        if (resValue != null) {
397
398            File xml = new File(resValue.getValue());
399            if (xml.isFile()) {
400                // we need to create a pull parser around the layout XML file, and then
401                // give that to our XmlBlockParser
402                try {
403                    XmlPullParser parser = ParserFactory.create(xml);
404
405                    // set the resource ref to have correct view cookies
406                    mBridgeInflater.setResourceReference(resource);
407
408                    BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
409                            this, resource.isFramework());
410                    try {
411                        pushParser(blockParser);
412                        return Pair.of(
413                                mBridgeInflater.inflate(blockParser, parent, attachToRoot),
414                                false);
415                    } finally {
416                        popParser();
417                    }
418                } catch (XmlPullParserException e) {
419                    Bridge.getLog().error(LayoutLog.TAG_BROKEN,
420                            "Failed to configure parser for " + xml, e, null /*data*/);
421                    // we'll return null below.
422                } catch (FileNotFoundException e) {
423                    // this shouldn't happen since we check above.
424                } finally {
425                    mBridgeInflater.setResourceReference(null);
426                }
427            } else {
428                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
429                        String.format("File %s is missing!", xml), null);
430            }
431        } else {
432            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
433                    String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
434                            resource.getName()), null);
435        }
436
437        return Pair.of(null, false);
438    }
439
440    @SuppressWarnings("deprecation")
441    private ILayoutPullParser getParser(ResourceReference resource) {
442        ILayoutPullParser parser;
443        if (resource instanceof ResourceValue) {
444            parser = mLayoutlibCallback.getParser((ResourceValue) resource);
445        } else {
446            parser = mLayoutlibCallback.getParser(resource.getName());
447        }
448        return parser;
449    }
450
451    // ------------ Context methods
452
453    @Override
454    public Resources getResources() {
455        return mSystemResources;
456    }
457
458    @Override
459    public Theme getTheme() {
460        return mTheme;
461    }
462
463    @Override
464    public ClassLoader getClassLoader() {
465        return this.getClass().getClassLoader();
466    }
467
468    @Override
469    public Object getSystemService(String service) {
470        if (LAYOUT_INFLATER_SERVICE.equals(service)) {
471            return mBridgeInflater;
472        }
473
474        if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) {
475            // we need to return a valid service to avoid NPE
476            return TextServicesManager.getInstance();
477        }
478
479        if (WINDOW_SERVICE.equals(service)) {
480            return mWindowManager;
481        }
482
483        // needed by SearchView
484        if (INPUT_METHOD_SERVICE.equals(service)) {
485            return null;
486        }
487
488        if (POWER_SERVICE.equals(service)) {
489            return new PowerManager(this, new BridgePowerManager(), new Handler());
490        }
491
492        if (DISPLAY_SERVICE.equals(service)) {
493            return mDisplayManager;
494        }
495
496        if (ACCESSIBILITY_SERVICE.equals(service)) {
497            return AccessibilityManager.getInstance(this);
498        }
499
500        throw new UnsupportedOperationException("Unsupported Service: " + service);
501    }
502
503    @Override
504    public String getSystemServiceName(Class<?> serviceClass) {
505        if (serviceClass.equals(LayoutInflater.class)) {
506            return LAYOUT_INFLATER_SERVICE;
507        }
508
509        if (serviceClass.equals(TextServicesManager.class)) {
510            return TEXT_SERVICES_MANAGER_SERVICE;
511        }
512
513        if (serviceClass.equals(WindowManager.class)) {
514            return WINDOW_SERVICE;
515        }
516
517        if (serviceClass.equals(PowerManager.class)) {
518            return POWER_SERVICE;
519        }
520
521        if (serviceClass.equals(DisplayManager.class)) {
522            return DISPLAY_SERVICE;
523        }
524
525        if (serviceClass.equals(AccessibilityManager.class)) {
526            return ACCESSIBILITY_SERVICE;
527        }
528
529        throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
530    }
531
532    @Override
533    public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
534        // No style is specified here, so create the typed array based on the default theme
535        // and the styles already applied to it. A null value of style indicates that the default
536        // theme should be used.
537        return createStyleBasedTypedArray(null, attrs);
538    }
539
540    @Override
541    public final BridgeTypedArray obtainStyledAttributes(int resid, int[] attrs)
542            throws Resources.NotFoundException {
543        StyleResourceValue style = null;
544        // get the StyleResourceValue based on the resId;
545        if (resid != 0) {
546            style = getStyleByDynamicId(resid);
547
548            if (style == null) {
549                // In some cases, style may not be a dynamic id, so we do a full search.
550                ResourceReference ref = resolveId(resid);
551                if (ref != null) {
552                    style = mRenderResources.getStyle(ref.getName(), ref.isFramework());
553                }
554            }
555
556            if (style == null) {
557                throw new Resources.NotFoundException();
558            }
559        }
560
561        if (mTypedArrayCache == null) {
562            mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>();
563
564            Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>();
565            mTypedArrayCache.put(attrs, map);
566
567            BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
568            map.put(resid, ta);
569
570            return ta;
571        }
572
573        // get the 2nd map
574        Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs);
575        if (map == null) {
576            map = new HashMap<Integer, BridgeTypedArray>();
577            mTypedArrayCache.put(attrs, map);
578        }
579
580        // get the array from the 2nd map
581        BridgeTypedArray ta = map.get(resid);
582
583        if (ta == null) {
584            ta = createStyleBasedTypedArray(style, attrs);
585            map.put(resid, ta);
586        }
587
588        return ta;
589    }
590
591    @Override
592    public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
593        return obtainStyledAttributes(set, attrs, 0, 0);
594    }
595
596    @Override
597    public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
598            int defStyleAttr, int defStyleRes) {
599
600        Map<String, String> defaultPropMap = null;
601        boolean isPlatformFile = true;
602
603        // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
604        if (set instanceof BridgeXmlBlockParser) {
605            BridgeXmlBlockParser parser;
606            parser = (BridgeXmlBlockParser)set;
607
608            isPlatformFile = parser.isPlatformFile();
609
610            Object key = parser.getViewCookie();
611            if (key != null) {
612                defaultPropMap = mDefaultPropMaps.get(key);
613                if (defaultPropMap == null) {
614                    defaultPropMap = new HashMap<String, String>();
615                    mDefaultPropMaps.put(key, defaultPropMap);
616                }
617            }
618
619        } else if (set instanceof BridgeLayoutParamsMapAttributes) {
620            // this is only for temp layout params generated dynamically, so this is never
621            // platform content.
622            isPlatformFile = false;
623        } else if (set != null) { // null parser is ok
624            // really this should not be happening since its instantiated in Bridge
625            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
626                    "Parser is not a BridgeXmlBlockParser!", null);
627            return null;
628        }
629
630        List<Pair<String, Boolean>> attributeList = searchAttrs(attrs);
631
632        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
633                isPlatformFile);
634
635        // look for a custom style.
636        String customStyle = null;
637        if (set != null) {
638            customStyle = set.getAttributeValue(null, "style");
639        }
640
641        StyleResourceValue customStyleValues = null;
642        if (customStyle != null) {
643            ResourceValue item = mRenderResources.findResValue(customStyle,
644                    isPlatformFile /*forceFrameworkOnly*/);
645
646            // resolve it in case it links to something else
647            item = mRenderResources.resolveResValue(item);
648
649            if (item instanceof StyleResourceValue) {
650                customStyleValues = (StyleResourceValue)item;
651            }
652        }
653
654        // resolve the defStyleAttr value into a IStyleResourceValue
655        StyleResourceValue defStyleValues = null;
656
657        if (defStyleAttr != 0) {
658            // get the name from the int.
659            Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
660
661            if (defStyleAttribute == null) {
662                // This should be rare. Happens trying to map R.style.foo to @style/foo fails.
663                // This will happen if the user explicitly used a non existing int value for
664                // defStyleAttr or there's something wrong with the project structure/build.
665                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
666                        "Failed to find the style corresponding to the id " + defStyleAttr, null);
667            } else {
668                if (defaultPropMap != null) {
669                    String defStyleName = defStyleAttribute.getFirst();
670                    if (defStyleAttribute.getSecond()) {
671                        defStyleName = "android:" + defStyleName;
672                    }
673                    defaultPropMap.put("style", defStyleName);
674                }
675
676                // look for the style in the current theme, and its parent:
677                ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
678                        defStyleAttribute.getSecond());
679
680                if (item != null) {
681                    // item is a reference to a style entry. Search for it.
682                    item = mRenderResources.findResValue(item.getValue(), item.isFramework());
683
684                    if (item instanceof StyleResourceValue) {
685                        defStyleValues = (StyleResourceValue) item;
686                    }
687                } else {
688                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
689                            String.format(
690                                    "Failed to find style '%s' in current theme",
691                                    defStyleAttribute.getFirst()),
692                            null);
693                }
694            }
695        } else if (defStyleRes != 0) {
696            boolean isFrameworkRes = true;
697            Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
698            if (value == null) {
699                value = mLayoutlibCallback.resolveResourceId(defStyleRes);
700                isFrameworkRes = false;
701            }
702
703            if (value != null) {
704                if ((value.getFirst() == ResourceType.STYLE)) {
705                    // look for the style in all resources:
706                    StyleResourceValue item = mRenderResources.getStyle(value.getSecond(),
707                            isFrameworkRes);
708                    if (item != null) {
709                        if (defaultPropMap != null) {
710                            defaultPropMap.put("style", item.getName());
711                        }
712
713                        defStyleValues = item;
714                    } else {
715                        Bridge.getLog().error(null,
716                                String.format(
717                                        "Style with id 0x%x (resolved to '%s') does not exist.",
718                                        defStyleRes, value.getSecond()),
719                                null);
720                    }
721                } else {
722                    Bridge.getLog().error(null,
723                            String.format(
724                                    "Resource id 0x%x is not of type STYLE (instead %s)",
725                                    defStyleRes, value.getFirst().toString()),
726                            null);
727                }
728            } else {
729                Bridge.getLog().error(null,
730                        String.format(
731                                "Failed to find style with id 0x%x in current theme",
732                                defStyleRes),
733                        null);
734            }
735        }
736
737        String appNamespace = mLayoutlibCallback.getNamespace();
738
739        if (attributeList != null) {
740            for (int index = 0 ; index < attributeList.size() ; index++) {
741                Pair<String, Boolean> attribute = attributeList.get(index);
742
743                if (attribute == null) {
744                    continue;
745                }
746
747                String attrName = attribute.getFirst();
748                boolean frameworkAttr = attribute.getSecond();
749                String value = null;
750                if (set != null) {
751                    value = set.getAttributeValue(
752                            frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace,
753                                    attrName);
754
755                    // if this is an app attribute, and the first get fails, try with the
756                    // new res-auto namespace as well
757                    if (!frameworkAttr && value == null) {
758                        value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
759                    }
760                }
761
762                // if there's no direct value for this attribute in the XML, we look for default
763                // values in the widget defStyle, and then in the theme.
764                if (value == null) {
765                    ResourceValue resValue = null;
766
767                    // look for the value in the custom style first (and its parent if needed)
768                    if (customStyleValues != null) {
769                        resValue = mRenderResources.findItemInStyle(customStyleValues,
770                                attrName, frameworkAttr);
771                    }
772
773                    // then look for the value in the default Style (and its parent if needed)
774                    if (resValue == null && defStyleValues != null) {
775                        resValue = mRenderResources.findItemInStyle(defStyleValues,
776                                attrName, frameworkAttr);
777                    }
778
779                    // if the item is not present in the defStyle, we look in the main theme (and
780                    // its parent themes)
781                    if (resValue == null) {
782                        resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
783                    }
784
785                    // if we found a value, we make sure this doesn't reference another value.
786                    // So we resolve it.
787                    if (resValue != null) {
788                        // put the first default value, before the resolution.
789                        if (defaultPropMap != null) {
790                            defaultPropMap.put(attrName, resValue.getValue());
791                        }
792
793                        resValue = mRenderResources.resolveResValue(resValue);
794                    }
795
796                    ta.bridgeSetValue(index, attrName, frameworkAttr, resValue);
797                } else {
798                    // there is a value in the XML, but we need to resolve it in case it's
799                    // referencing another resource or a theme value.
800                    ta.bridgeSetValue(index, attrName, frameworkAttr,
801                            mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
802                }
803            }
804        }
805
806        ta.sealArray();
807
808        return ta;
809    }
810
811    @Override
812    public Looper getMainLooper() {
813        return Looper.myLooper();
814    }
815
816
817    @Override
818    public String getPackageName() {
819        if (mApplicationInfo.packageName == null) {
820            mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE);
821        }
822        return mApplicationInfo.packageName;
823    }
824
825    // ------------- private new methods
826
827    /**
828     * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
829     * values found in the given style. If no style is specified, the default theme, along with the
830     * styles applied to it are used.
831     *
832     * @see #obtainStyledAttributes(int, int[])
833     */
834    private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style,
835            int[] attrs) throws Resources.NotFoundException {
836
837        List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
838
839        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
840                false);
841
842        // for each attribute, get its name so that we can search it in the style
843        for (int i = 0 ; i < attrs.length ; i++) {
844            Pair<String, Boolean> attribute = attributes.get(i);
845
846            if (attribute != null) {
847                // look for the value in the given style
848                ResourceValue resValue;
849                if (style != null) {
850                    resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(),
851                            attribute.getSecond());
852                } else {
853                    resValue = mRenderResources.findItemInTheme(attribute.getFirst(),
854                            attribute.getSecond());
855                }
856
857                if (resValue != null) {
858                    // resolve it to make sure there are no references left.
859                    ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(),
860                            mRenderResources.resolveResValue(resValue));
861                }
862            }
863        }
864
865        ta.sealArray();
866
867        return ta;
868    }
869
870    /**
871     * The input int[] attrs is a list of attributes. The returns a list of information about
872     * each attributes. The information is (name, isFramework)
873     * <p/>
874     *
875     * @param attrs An attribute array reference given to obtainStyledAttributes.
876     * @return List of attribute information.
877     */
878    private List<Pair<String, Boolean>> searchAttrs(int[] attrs) {
879        List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length);
880
881        // for each attribute, get its name so that we can search it in the style
882        for (int attr : attrs) {
883            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr);
884            boolean isFramework = false;
885            if (resolvedResource != null) {
886                isFramework = true;
887            } else {
888                resolvedResource = mLayoutlibCallback.resolveResourceId(attr);
889            }
890
891            if (resolvedResource != null) {
892                results.add(Pair.of(resolvedResource.getSecond(), isFramework));
893            } else {
894                results.add(null);
895            }
896        }
897
898        return results;
899    }
900
901    /**
902     * Searches for the attribute referenced by its internal id.
903     *
904     * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
905     * @return A (name, isFramework) pair describing the attribute if found. Returns null
906     *         if nothing is found.
907     */
908    public Pair<String, Boolean> searchAttr(int attr) {
909        Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
910        if (info != null) {
911            return Pair.of(info.getSecond(), Boolean.TRUE);
912        }
913
914        info = mLayoutlibCallback.resolveResourceId(attr);
915        if (info != null) {
916            return Pair.of(info.getSecond(), Boolean.FALSE);
917        }
918
919        return null;
920    }
921
922    public int getDynamicIdByStyle(StyleResourceValue resValue) {
923        if (mDynamicIdToStyleMap == null) {
924            // create the maps.
925            mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
926            mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
927        }
928
929        // look for an existing id
930        Integer id = mStyleToDynamicIdMap.get(resValue);
931
932        if (id == null) {
933            // generate a new id
934            id = ++mDynamicIdGenerator;
935
936            // and add it to the maps.
937            mDynamicIdToStyleMap.put(id, resValue);
938            mStyleToDynamicIdMap.put(resValue, id);
939        }
940
941        return id;
942    }
943
944    private StyleResourceValue getStyleByDynamicId(int i) {
945        if (mDynamicIdToStyleMap != null) {
946            return mDynamicIdToStyleMap.get(i);
947        }
948
949        return null;
950    }
951
952    public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
953        if (getRenderResources().getFrameworkResource(resType, resName) != null) {
954            // Bridge.getResourceId creates a new resource id if an existing one isn't found. So,
955            // we check for the existence of the resource before calling it.
956            return Bridge.getResourceId(resType, resName);
957        }
958
959        return defValue;
960    }
961
962    public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
963        // getResourceId creates a new resource id if an existing resource id isn't found. So, we
964        // check for the existence of the resource before calling it.
965        if (getRenderResources().getProjectResource(resType, resName) != null) {
966            if (mLayoutlibCallback != null) {
967                Integer value = mLayoutlibCallback.getResourceId(resType, resName);
968                if (value != null) {
969                    return value;
970                }
971            }
972        }
973
974        return defValue;
975    }
976
977    public static Context getBaseContext(Context context) {
978        while (context instanceof ContextWrapper) {
979            context = ((ContextWrapper) context).getBaseContext();
980        }
981        return context;
982    }
983
984    //------------ NOT OVERRIDEN --------------------
985
986    @Override
987    public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
988        // pass
989        return false;
990    }
991
992    @Override
993    public int checkCallingOrSelfPermission(String arg0) {
994        // pass
995        return 0;
996    }
997
998    @Override
999    public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
1000        // pass
1001        return 0;
1002    }
1003
1004    @Override
1005    public int checkCallingPermission(String arg0) {
1006        // pass
1007        return 0;
1008    }
1009
1010    @Override
1011    public int checkCallingUriPermission(Uri arg0, int arg1) {
1012        // pass
1013        return 0;
1014    }
1015
1016    @Override
1017    public int checkPermission(String arg0, int arg1, int arg2) {
1018        // pass
1019        return 0;
1020    }
1021
1022    @Override
1023    public int checkSelfPermission(String arg0) {
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    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1409            String receiverPermission, int appOp) {
1410        // pass
1411    }
1412
1413    @Override
1414    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1415            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
1416            int initialCode, String initialData, Bundle initialExtras) {
1417        // pass
1418    }
1419
1420    @Override
1421    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1422            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
1423            Handler scheduler,
1424            int initialCode, String initialData, Bundle initialExtras) {
1425        // pass
1426    }
1427
1428    @Override
1429    public void sendStickyBroadcast(Intent arg0) {
1430        // pass
1431
1432    }
1433
1434    @Override
1435    public void sendStickyOrderedBroadcast(Intent intent,
1436            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1437           Bundle initialExtras) {
1438        // pass
1439    }
1440
1441    @Override
1442    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
1443        // pass
1444    }
1445
1446    @Override
1447    public void sendStickyOrderedBroadcastAsUser(Intent intent,
1448            UserHandle user, BroadcastReceiver resultReceiver,
1449            Handler scheduler, int initialCode, String initialData,
1450            Bundle initialExtras) {
1451        // pass
1452    }
1453
1454    @Override
1455    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
1456        // pass
1457    }
1458
1459    @Override
1460    public void setTheme(int arg0) {
1461        // pass
1462
1463    }
1464
1465    @Override
1466    public void setWallpaper(Bitmap arg0) throws IOException {
1467        // pass
1468
1469    }
1470
1471    @Override
1472    public void setWallpaper(InputStream arg0) throws IOException {
1473        // pass
1474
1475    }
1476
1477    @Override
1478    public void startActivity(Intent arg0) {
1479        // pass
1480    }
1481
1482    @Override
1483    public void startActivity(Intent arg0, Bundle arg1) {
1484        // pass
1485    }
1486
1487    @Override
1488    public void startIntentSender(IntentSender intent,
1489            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1490            throws IntentSender.SendIntentException {
1491        // pass
1492    }
1493
1494    @Override
1495    public void startIntentSender(IntentSender intent,
1496            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1497            Bundle options) throws IntentSender.SendIntentException {
1498        // pass
1499    }
1500
1501    @Override
1502    public boolean startInstrumentation(ComponentName arg0, String arg1,
1503            Bundle arg2) {
1504        // pass
1505        return false;
1506    }
1507
1508    @Override
1509    public ComponentName startService(Intent arg0) {
1510        // pass
1511        return null;
1512    }
1513
1514    @Override
1515    public boolean stopService(Intent arg0) {
1516        // pass
1517        return false;
1518    }
1519
1520    @Override
1521    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
1522        // pass
1523        return null;
1524    }
1525
1526    @Override
1527    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
1528        // pass
1529        return false;
1530    }
1531
1532    @Override
1533    public void unbindService(ServiceConnection arg0) {
1534        // pass
1535
1536    }
1537
1538    @Override
1539    public void unregisterReceiver(BroadcastReceiver arg0) {
1540        // pass
1541
1542    }
1543
1544    @Override
1545    public Context getApplicationContext() {
1546        return this;
1547    }
1548
1549    @Override
1550    public void startActivities(Intent[] arg0) {
1551        // pass
1552
1553    }
1554
1555    @Override
1556    public void startActivities(Intent[] arg0, Bundle arg1) {
1557        // pass
1558
1559    }
1560
1561    @Override
1562    public boolean isRestricted() {
1563        return false;
1564    }
1565
1566    @Override
1567    public File getObbDir() {
1568        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1569        return null;
1570    }
1571
1572    @Override
1573    public DisplayAdjustments getDisplayAdjustments(int displayId) {
1574        // pass
1575        return null;
1576    }
1577
1578    @Override
1579    public int getUserId() {
1580        return 0; // not used
1581    }
1582
1583    @Override
1584    public File[] getExternalFilesDirs(String type) {
1585        // pass
1586        return new File[0];
1587    }
1588
1589    @Override
1590    public File[] getObbDirs() {
1591        // pass
1592        return new File[0];
1593    }
1594
1595    @Override
1596    public File[] getExternalCacheDirs() {
1597        // pass
1598        return new File[0];
1599    }
1600
1601    @Override
1602    public File[] getExternalMediaDirs() {
1603        // pass
1604        return new File[0];
1605    }
1606}
1607