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