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