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