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 Context createApplicationContext(ApplicationInfo application, int flags)
971            throws PackageManager.NameNotFoundException {
972        return null;
973    }
974
975    @Override
976    public boolean deleteDatabase(String arg0) {
977        // pass
978        return false;
979    }
980
981    @Override
982    public boolean deleteFile(String arg0) {
983        // pass
984        return false;
985    }
986
987    @Override
988    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
989        // pass
990
991    }
992
993    @Override
994    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
995            String arg2) {
996        // pass
997
998    }
999
1000    @Override
1001    public void enforceCallingPermission(String arg0, String arg1) {
1002        // pass
1003
1004    }
1005
1006    @Override
1007    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
1008        // pass
1009
1010    }
1011
1012    @Override
1013    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
1014        // pass
1015
1016    }
1017
1018    @Override
1019    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
1020            String arg4) {
1021        // pass
1022
1023    }
1024
1025    @Override
1026    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
1027            int arg3, int arg4, int arg5, String arg6) {
1028        // pass
1029
1030    }
1031
1032    @Override
1033    public String[] fileList() {
1034        // pass
1035        return null;
1036    }
1037
1038    @Override
1039    public AssetManager getAssets() {
1040        // pass
1041        return null;
1042    }
1043
1044    @Override
1045    public File getCacheDir() {
1046        // pass
1047        return null;
1048    }
1049
1050    @Override
1051    public File getCodeCacheDir() {
1052        // pass
1053        return null;
1054    }
1055
1056    @Override
1057    public File getExternalCacheDir() {
1058        // pass
1059        return null;
1060    }
1061
1062    @Override
1063    public ContentResolver getContentResolver() {
1064        if (mContentResolver == null) {
1065            mContentResolver = new BridgeContentResolver(this);
1066        }
1067        return mContentResolver;
1068    }
1069
1070    @Override
1071    public File getDatabasePath(String arg0) {
1072        // pass
1073        return null;
1074    }
1075
1076    @Override
1077    public File getDir(String arg0, int arg1) {
1078        // pass
1079        return null;
1080    }
1081
1082    @Override
1083    public File getFileStreamPath(String arg0) {
1084        // pass
1085        return null;
1086    }
1087
1088    @Override
1089    public File getFilesDir() {
1090        // pass
1091        return null;
1092    }
1093
1094    @Override
1095    public File getNoBackupFilesDir() {
1096        // pass
1097        return null;
1098    }
1099
1100    @Override
1101    public File getExternalFilesDir(String type) {
1102        // pass
1103        return null;
1104    }
1105
1106    @Override
1107    public String getPackageCodePath() {
1108        // pass
1109        return null;
1110    }
1111
1112    @Override
1113    public PackageManager getPackageManager() {
1114        // pass
1115        return null;
1116    }
1117
1118    @Override
1119    public String getPackageName() {
1120        // pass
1121        return null;
1122    }
1123
1124    @Override
1125    public String getBasePackageName() {
1126        // pass
1127        return null;
1128    }
1129
1130    @Override
1131    public String getOpPackageName() {
1132        // pass
1133        return null;
1134    }
1135
1136    @Override
1137    public ApplicationInfo getApplicationInfo() {
1138        return mApplicationInfo;
1139    }
1140
1141    @Override
1142    public String getPackageResourcePath() {
1143        // pass
1144        return null;
1145    }
1146
1147    @Override
1148    public File getSharedPrefsFile(String name) {
1149        // pass
1150        return null;
1151    }
1152
1153    @Override
1154    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1155        // pass
1156        return null;
1157    }
1158
1159    @Override
1160    public Drawable getWallpaper() {
1161        // pass
1162        return null;
1163    }
1164
1165    @Override
1166    public int getWallpaperDesiredMinimumWidth() {
1167        return -1;
1168    }
1169
1170    @Override
1171    public int getWallpaperDesiredMinimumHeight() {
1172        return -1;
1173    }
1174
1175    @Override
1176    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1177        // pass
1178
1179    }
1180
1181    @Override
1182    public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1183        // pass
1184        return null;
1185    }
1186
1187    @Override
1188    public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1189        // pass
1190        return null;
1191    }
1192
1193    @Override
1194    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1195        // pass
1196        return null;
1197    }
1198
1199    @Override
1200    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1201            CursorFactory arg2, DatabaseErrorHandler arg3) {
1202        // pass
1203        return null;
1204    }
1205
1206    @Override
1207    public Drawable peekWallpaper() {
1208        // pass
1209        return null;
1210    }
1211
1212    @Override
1213    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1214        // pass
1215        return null;
1216    }
1217
1218    @Override
1219    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1220            String arg2, Handler arg3) {
1221        // pass
1222        return null;
1223    }
1224
1225    @Override
1226    public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
1227            IntentFilter arg1, String arg2, Handler arg3) {
1228        // pass
1229        return null;
1230    }
1231
1232    @Override
1233    public void removeStickyBroadcast(Intent arg0) {
1234        // pass
1235
1236    }
1237
1238    @Override
1239    public void revokeUriPermission(Uri arg0, int arg1) {
1240        // pass
1241
1242    }
1243
1244    @Override
1245    public void sendBroadcast(Intent arg0) {
1246        // pass
1247
1248    }
1249
1250    @Override
1251    public void sendBroadcast(Intent arg0, String arg1) {
1252        // pass
1253
1254    }
1255
1256    @Override
1257    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
1258        // pass
1259    }
1260
1261    @Override
1262    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1263        // pass
1264
1265    }
1266
1267    @Override
1268    public void sendOrderedBroadcast(Intent arg0, String arg1,
1269            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1270            Bundle arg6) {
1271        // pass
1272
1273    }
1274
1275    @Override
1276    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
1277            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
1278            String initialData, Bundle initialExtras) {
1279        // pass
1280    }
1281
1282    @Override
1283    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
1284        // pass
1285    }
1286
1287    @Override
1288    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1289            String receiverPermission) {
1290        // pass
1291    }
1292
1293    @Override
1294    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1295            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
1296            int initialCode, String initialData, Bundle initialExtras) {
1297        // pass
1298    }
1299
1300    @Override
1301    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1302            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
1303            Handler scheduler,
1304            int initialCode, String initialData, Bundle initialExtras) {
1305        // pass
1306    }
1307
1308    @Override
1309    public void sendStickyBroadcast(Intent arg0) {
1310        // pass
1311
1312    }
1313
1314    @Override
1315    public void sendStickyOrderedBroadcast(Intent intent,
1316            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1317           Bundle initialExtras) {
1318        // pass
1319    }
1320
1321    @Override
1322    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
1323        // pass
1324    }
1325
1326    @Override
1327    public void sendStickyOrderedBroadcastAsUser(Intent intent,
1328            UserHandle user, BroadcastReceiver resultReceiver,
1329            Handler scheduler, int initialCode, String initialData,
1330            Bundle initialExtras) {
1331        // pass
1332    }
1333
1334    @Override
1335    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
1336        // pass
1337    }
1338
1339    @Override
1340    public void setTheme(int arg0) {
1341        // pass
1342
1343    }
1344
1345    @Override
1346    public void setWallpaper(Bitmap arg0) throws IOException {
1347        // pass
1348
1349    }
1350
1351    @Override
1352    public void setWallpaper(InputStream arg0) throws IOException {
1353        // pass
1354
1355    }
1356
1357    @Override
1358    public void startActivity(Intent arg0) {
1359        // pass
1360    }
1361
1362    @Override
1363    public void startActivity(Intent arg0, Bundle arg1) {
1364        // pass
1365    }
1366
1367    @Override
1368    public void startIntentSender(IntentSender intent,
1369            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1370            throws IntentSender.SendIntentException {
1371        // pass
1372    }
1373
1374    @Override
1375    public void startIntentSender(IntentSender intent,
1376            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1377            Bundle options) throws IntentSender.SendIntentException {
1378        // pass
1379    }
1380
1381    @Override
1382    public boolean startInstrumentation(ComponentName arg0, String arg1,
1383            Bundle arg2) {
1384        // pass
1385        return false;
1386    }
1387
1388    @Override
1389    public ComponentName startService(Intent arg0) {
1390        // pass
1391        return null;
1392    }
1393
1394    @Override
1395    public boolean stopService(Intent arg0) {
1396        // pass
1397        return false;
1398    }
1399
1400    @Override
1401    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
1402        // pass
1403        return null;
1404    }
1405
1406    @Override
1407    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
1408        // pass
1409        return false;
1410    }
1411
1412    @Override
1413    public void unbindService(ServiceConnection arg0) {
1414        // pass
1415
1416    }
1417
1418    @Override
1419    public void unregisterReceiver(BroadcastReceiver arg0) {
1420        // pass
1421
1422    }
1423
1424    @Override
1425    public Context getApplicationContext() {
1426        return this;
1427    }
1428
1429    @Override
1430    public void startActivities(Intent[] arg0) {
1431        // pass
1432
1433    }
1434
1435    @Override
1436    public void startActivities(Intent[] arg0, Bundle arg1) {
1437        // pass
1438
1439    }
1440
1441    @Override
1442    public boolean isRestricted() {
1443        return false;
1444    }
1445
1446    @Override
1447    public File getObbDir() {
1448        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1449        return null;
1450    }
1451
1452    @Override
1453    public DisplayAdjustments getDisplayAdjustments(int displayId) {
1454        // pass
1455        return null;
1456    }
1457
1458    /**
1459     * @hide
1460     */
1461    @Override
1462    public int getUserId() {
1463        return 0; // not used
1464    }
1465
1466    @Override
1467    public File[] getExternalFilesDirs(String type) {
1468        // pass
1469        return new File[0];
1470    }
1471
1472    @Override
1473    public File[] getObbDirs() {
1474        // pass
1475        return new File[0];
1476    }
1477
1478    @Override
1479    public File[] getExternalCacheDirs() {
1480        // pass
1481        return new File[0];
1482    }
1483
1484    @Override
1485    public File[] getExternalMediaDirs() {
1486        // pass
1487        return new File[0];
1488    }
1489}
1490