BridgeContext.java revision 58658eaa642012733a36676b01f6d53b2f662e06
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.SdkConstants;
20import com.android.ide.common.rendering.api.AssetRepository;
21import com.android.ide.common.rendering.api.ILayoutPullParser;
22import com.android.ide.common.rendering.api.LayoutLog;
23import com.android.ide.common.rendering.api.LayoutlibCallback;
24import com.android.ide.common.rendering.api.RenderResources;
25import com.android.ide.common.rendering.api.ResourceReference;
26import com.android.ide.common.rendering.api.ResourceValue;
27import com.android.ide.common.rendering.api.StyleResourceValue;
28import com.android.layoutlib.bridge.Bridge;
29import com.android.layoutlib.bridge.BridgeConstants;
30import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
31import com.android.layoutlib.bridge.impl.ParserFactory;
32import com.android.layoutlib.bridge.impl.Stack;
33import com.android.resources.ResourceType;
34import com.android.util.Pair;
35import com.android.util.PropertiesMap;
36import com.android.util.PropertiesMap.Property;
37
38import org.xmlpull.v1.XmlPullParser;
39import org.xmlpull.v1.XmlPullParserException;
40
41import android.annotation.NonNull;
42import android.annotation.Nullable;
43import android.content.BroadcastReceiver;
44import android.content.ComponentName;
45import android.content.ContentResolver;
46import android.content.Context;
47import android.content.ContextWrapper;
48import android.content.Intent;
49import android.content.IntentFilter;
50import android.content.IntentSender;
51import android.content.ServiceConnection;
52import android.content.SharedPreferences;
53import android.content.pm.ApplicationInfo;
54import android.content.pm.PackageManager;
55import android.content.res.AssetManager;
56import android.content.res.BridgeAssetManager;
57import android.content.res.BridgeTypedArray;
58import android.content.res.Configuration;
59import android.content.res.Resources;
60import android.content.res.Resources.Theme;
61import android.content.res.Resources_Delegate;
62import android.database.DatabaseErrorHandler;
63import android.database.sqlite.SQLiteDatabase;
64import android.database.sqlite.SQLiteDatabase.CursorFactory;
65import android.graphics.Bitmap;
66import android.graphics.drawable.Drawable;
67import android.hardware.display.DisplayManager;
68import android.net.Uri;
69import android.os.Build.VERSION_CODES;
70import android.os.Bundle;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IInterface;
74import android.os.Looper;
75import android.os.Parcel;
76import android.os.PowerManager;
77import android.os.RemoteException;
78import android.os.ResultReceiver;
79import android.os.UserHandle;
80import android.util.AttributeSet;
81import android.util.DisplayMetrics;
82import android.util.TypedValue;
83import android.view.BridgeInflater;
84import android.view.Display;
85import android.view.DisplayAdjustments;
86import android.view.LayoutInflater;
87import android.view.View;
88import android.view.ViewGroup;
89import android.view.WindowManager;
90import android.view.accessibility.AccessibilityManager;
91import android.view.textservice.TextServicesManager;
92
93import java.io.File;
94import java.io.FileDescriptor;
95import java.io.FileInputStream;
96import java.io.FileNotFoundException;
97import java.io.FileOutputStream;
98import java.io.IOException;
99import java.io.InputStream;
100import java.util.ArrayList;
101import java.util.HashMap;
102import java.util.IdentityHashMap;
103import java.util.List;
104import java.util.Map;
105
106import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
107
108/**
109 * Custom implementation of Context/Activity to handle non compiled resources.
110 */
111@SuppressWarnings("deprecation")  // For use of Pair.
112public final class BridgeContext extends Context {
113    private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
114
115    /** The map adds cookies to each view so that IDE can link xml tags to views. */
116    private final HashMap<View, Object> mViewKeyMap = new HashMap<>();
117    /**
118     * In some cases, when inflating an xml, some objects are created. Then later, the objects are
119     * converted to views. This map stores the mapping from objects to cookies which can then be
120     * used to populate the mViewKeyMap.
121     */
122    private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<>();
123    private final BridgeAssetManager mAssets;
124    private Resources mSystemResources;
125    private final Object mProjectKey;
126    private final DisplayMetrics mMetrics;
127    private final RenderResources mRenderResources;
128    private final Configuration mConfig;
129    private final ApplicationInfo mApplicationInfo;
130    private final LayoutlibCallback mLayoutlibCallback;
131    private final WindowManager mWindowManager;
132    private final DisplayManager mDisplayManager;
133    private final HashMap<View, Integer> mScrollYPos = new HashMap<>();
134    private final HashMap<View, Integer> mScrollXPos = new HashMap<>();
135
136    private Resources.Theme mTheme;
137
138    private final Map<Object, PropertiesMap> mDefaultPropMaps = new IdentityHashMap<>();
139
140    // maps for dynamically generated id representing style objects (StyleResourceValue)
141    @Nullable
142    private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
143    private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
144    private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
145
146    // cache for TypedArray generated from StyleResourceValue object
147    private TypedArrayCache mTypedArrayCache;
148    private BridgeInflater mBridgeInflater;
149
150    private BridgeContentResolver mContentResolver;
151
152    private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<>();
153    private SharedPreferences mSharedPreferences;
154    private ClassLoader mClassLoader;
155    private IBinder mBinder;
156    private PackageManager mPackageManager;
157    private Boolean mIsThemeAppCompat;
158
159    /**
160     * Some applications that target both pre API 17 and post API 17, set the newer attrs to
161     * reference the older ones. For example, android:paddingStart will resolve to
162     * android:paddingLeft. This way the apps need to only define paddingLeft at any other place.
163     * This a map from value to attribute name. Warning for missing references shouldn't be logged
164     * if value and attr name pair is the same as an entry in this map.
165     */
166    private static Map<String, String> RTL_ATTRS = new HashMap<>(10);
167
168    static {
169        RTL_ATTRS.put("?android:attr/paddingLeft", "paddingStart");
170        RTL_ATTRS.put("?android:attr/paddingRight", "paddingEnd");
171        RTL_ATTRS.put("?android:attr/layout_marginLeft", "layout_marginStart");
172        RTL_ATTRS.put("?android:attr/layout_marginRight", "layout_marginEnd");
173        RTL_ATTRS.put("?android:attr/layout_toLeftOf", "layout_toStartOf");
174        RTL_ATTRS.put("?android:attr/layout_toRightOf", "layout_toEndOf");
175        RTL_ATTRS.put("?android:attr/layout_alignParentLeft", "layout_alignParentStart");
176        RTL_ATTRS.put("?android:attr/layout_alignParentRight", "layout_alignParentEnd");
177        RTL_ATTRS.put("?android:attr/drawableLeft", "drawableStart");
178        RTL_ATTRS.put("?android:attr/drawableRight", "drawableEnd");
179    }
180
181    /**
182     * @param projectKey An Object identifying the project. This is used for the cache mechanism.
183     * @param metrics the {@link DisplayMetrics}.
184     * @param renderResources the configured resources (both framework and projects) for this
185     * render.
186     * @param config the Configuration object for this render.
187     * @param targetSdkVersion the targetSdkVersion of the application.
188     */
189    public BridgeContext(Object projectKey, DisplayMetrics metrics,
190            RenderResources renderResources,
191            AssetRepository assets,
192            LayoutlibCallback layoutlibCallback,
193            Configuration config,
194            int targetSdkVersion,
195            boolean hasRtlSupport) {
196        mProjectKey = projectKey;
197        mMetrics = metrics;
198        mLayoutlibCallback = layoutlibCallback;
199
200        mRenderResources = renderResources;
201        mConfig = config;
202        AssetManager systemAssetManager = AssetManager.getSystem();
203        if (systemAssetManager instanceof BridgeAssetManager) {
204            mAssets = (BridgeAssetManager) systemAssetManager;
205        } else {
206            throw new AssertionError("Creating BridgeContext without initializing Bridge");
207        }
208        mAssets.setAssetRepository(assets);
209
210        mApplicationInfo = new ApplicationInfo();
211        mApplicationInfo.targetSdkVersion = targetSdkVersion;
212        if (hasRtlSupport) {
213            mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
214        }
215
216        mWindowManager = new WindowManagerImpl(mMetrics);
217        mDisplayManager = new DisplayManager(this);
218    }
219
220    /**
221     * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
222     * {@link DisplayMetrics}, {@link Configuration}, and {@link LayoutlibCallback}.
223     *
224     * @see #disposeResources()
225     */
226    public void initResources() {
227        AssetManager assetManager = AssetManager.getSystem();
228
229        mSystemResources = Resources_Delegate.initSystem(
230                this,
231                assetManager,
232                mMetrics,
233                mConfig,
234                mLayoutlibCallback);
235        mTheme = mSystemResources.newTheme();
236    }
237
238    /**
239     * Disposes the {@link Resources} singleton.
240     */
241    public void disposeResources() {
242        Resources_Delegate.disposeSystem();
243    }
244
245    public void setBridgeInflater(BridgeInflater inflater) {
246        mBridgeInflater = inflater;
247    }
248
249    public void addViewKey(View view, Object viewKey) {
250        mViewKeyMap.put(view, viewKey);
251    }
252
253    public Object getViewKey(View view) {
254        return mViewKeyMap.get(view);
255    }
256
257    public void addCookie(Object o, Object cookie) {
258        mViewKeyHelpMap.put(o, cookie);
259    }
260
261    public Object getCookie(Object o) {
262        return mViewKeyHelpMap.get(o);
263    }
264
265    public Object getProjectKey() {
266        return mProjectKey;
267    }
268
269    public DisplayMetrics getMetrics() {
270        return mMetrics;
271    }
272
273    public LayoutlibCallback getLayoutlibCallback() {
274        return mLayoutlibCallback;
275    }
276
277    public RenderResources getRenderResources() {
278        return mRenderResources;
279    }
280
281    public Map<Object, PropertiesMap> getDefaultProperties() {
282        return mDefaultPropMaps;
283    }
284
285    public Configuration getConfiguration() {
286        return mConfig;
287    }
288
289    /**
290     * Adds a parser to the stack.
291     * @param parser the parser to add.
292     */
293    public void pushParser(BridgeXmlBlockParser parser) {
294        if (ParserFactory.LOG_PARSER) {
295            System.out.println("PUSH " + parser.getParser().toString());
296        }
297        mParserStack.push(parser);
298    }
299
300    /**
301     * Removes the parser at the top of the stack
302     */
303    public void popParser() {
304        BridgeXmlBlockParser parser = mParserStack.pop();
305        if (ParserFactory.LOG_PARSER) {
306            System.out.println("POPD " + parser.getParser().toString());
307        }
308    }
309
310    /**
311     * Returns the current parser at the top the of the stack.
312     * @return a parser or null.
313     */
314    public BridgeXmlBlockParser getCurrentParser() {
315        return mParserStack.peek();
316    }
317
318    /**
319     * Returns the previous parser.
320     * @return a parser or null if there isn't any previous parser
321     */
322    public BridgeXmlBlockParser getPreviousParser() {
323        if (mParserStack.size() < 2) {
324            return null;
325        }
326        return mParserStack.get(mParserStack.size() - 2);
327    }
328
329    public boolean resolveThemeAttribute(int resId, TypedValue outValue, boolean resolveRefs) {
330        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resId);
331        boolean isFrameworkRes = true;
332        if (resourceInfo == null) {
333            resourceInfo = mLayoutlibCallback.resolveResourceId(resId);
334            isFrameworkRes = false;
335        }
336
337        if (resourceInfo == null) {
338            return false;
339        }
340
341        ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(),
342                isFrameworkRes);
343        if (resolveRefs) {
344            value = mRenderResources.resolveResValue(value);
345        }
346
347        if (value == null) {
348            // unable to find the attribute.
349            return false;
350        }
351
352        // check if this is a style resource
353        if (value instanceof StyleResourceValue) {
354            // get the id that will represent this style.
355            outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value);
356            return true;
357        }
358
359        int a;
360        // if this is a framework value.
361        if (value.isFramework()) {
362            // look for idName in the android R classes.
363            // use 0 a default res value as it's not a valid id value.
364            a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
365        } else {
366            // look for idName in the project R class.
367            // use 0 a default res value as it's not a valid id value.
368            a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
369        }
370
371        if (a != 0) {
372            outValue.resourceId = a;
373            return true;
374        }
375
376        // If the value is not a valid reference, fallback to pass the value as a string.
377        outValue.string = value.getValue();
378        return true;
379    }
380
381
382    public ResourceReference resolveId(int id) {
383        // first get the String related to this id in the framework
384        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
385
386        if (resourceInfo != null) {
387            return new ResourceReference(resourceInfo.getSecond(), true);
388        }
389
390        // didn't find a match in the framework? look in the project.
391        if (mLayoutlibCallback != null) {
392            resourceInfo = mLayoutlibCallback.resolveResourceId(id);
393
394            if (resourceInfo != null) {
395                return new ResourceReference(resourceInfo.getSecond(), false);
396            }
397        }
398
399        // The base value for R.style is 0x01030000 and the custom style is 0x02030000.
400        // So, if the second byte is 03, it's probably a style.
401        if ((id >> 16 & 0xFF) == 0x03) {
402            return getStyleByDynamicId(id);
403        }
404        return null;
405    }
406
407    public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
408            boolean attachToRoot, boolean skipCallbackParser) {
409        boolean isPlatformLayout = resource.isFramework();
410
411        if (!isPlatformLayout && !skipCallbackParser) {
412            // check if the project callback can provide us with a custom parser.
413            ILayoutPullParser parser = getParser(resource);
414
415            if (parser != null) {
416                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
417                        this, resource.isFramework());
418                try {
419                    pushParser(blockParser);
420                    return Pair.of(
421                            mBridgeInflater.inflate(blockParser, parent, attachToRoot),
422                            Boolean.TRUE);
423                } finally {
424                    popParser();
425                }
426            }
427        }
428
429        ResourceValue resValue;
430        if (resource instanceof ResourceValue) {
431            resValue = (ResourceValue) resource;
432        } else {
433            if (isPlatformLayout) {
434                resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT,
435                        resource.getName());
436            } else {
437                resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT,
438                        resource.getName());
439            }
440        }
441
442        if (resValue != null) {
443
444            File xml = new File(resValue.getValue());
445            if (xml.isFile()) {
446                // we need to create a pull parser around the layout XML file, and then
447                // give that to our XmlBlockParser
448                try {
449                    XmlPullParser parser = ParserFactory.create(xml, true);
450
451                    // set the resource ref to have correct view cookies
452                    mBridgeInflater.setResourceReference(resource);
453
454                    BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
455                            this, resource.isFramework());
456                    try {
457                        pushParser(blockParser);
458                        return Pair.of(
459                                mBridgeInflater.inflate(blockParser, parent, attachToRoot),
460                                Boolean.FALSE);
461                    } finally {
462                        popParser();
463                    }
464                } catch (XmlPullParserException e) {
465                    Bridge.getLog().error(LayoutLog.TAG_BROKEN,
466                            "Failed to configure parser for " + xml, e, null /*data*/);
467                    // we'll return null below.
468                } catch (FileNotFoundException e) {
469                    // this shouldn't happen since we check above.
470                } finally {
471                    mBridgeInflater.setResourceReference(null);
472                }
473            } else {
474                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
475                        String.format("File %s is missing!", xml), null);
476            }
477        } else {
478            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
479                    String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
480                            resource.getName()), null);
481        }
482
483        return Pair.of(null, Boolean.FALSE);
484    }
485
486    /**
487     * Returns whether the current selected theme is based on AppCompat
488     */
489    public boolean isAppCompatTheme() {
490        // If a cached value exists, return it.
491        if (mIsThemeAppCompat != null) {
492            return mIsThemeAppCompat;
493        }
494        // Ideally, we should check if the corresponding activity extends
495        // android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
496        StyleResourceValue defaultTheme = mRenderResources.getDefaultTheme();
497        // We can't simply check for parent using resources.themeIsParentOf() since the
498        // inheritance structure isn't really what one would expect. The first common parent
499        // between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
500        boolean isThemeAppCompat = false;
501        for (int i = 0; i < 50; i++) {
502            if (defaultTheme == null) {
503                break;
504            }
505            // for loop ensures that we don't run into cyclic theme inheritance.
506            if (defaultTheme.getName().startsWith(PREFIX_THEME_APPCOMPAT)) {
507                isThemeAppCompat = true;
508                break;
509            }
510            defaultTheme = mRenderResources.getParent(defaultTheme);
511        }
512        mIsThemeAppCompat = isThemeAppCompat;
513        return isThemeAppCompat;
514    }
515
516    @SuppressWarnings("deprecation")
517    private ILayoutPullParser getParser(ResourceReference resource) {
518        ILayoutPullParser parser;
519        if (resource instanceof ResourceValue) {
520            parser = mLayoutlibCallback.getParser((ResourceValue) resource);
521        } else {
522            parser = mLayoutlibCallback.getParser(resource.getName());
523        }
524        return parser;
525    }
526
527    // ------------ Context methods
528
529    @Override
530    public Resources getResources() {
531        return mSystemResources;
532    }
533
534    @Override
535    public Theme getTheme() {
536        return mTheme;
537    }
538
539    @Override
540    public ClassLoader getClassLoader() {
541        // The documentation for this method states that it should return a class loader one can
542        // use to retrieve classes in this package. However, when called by LayoutInflater, we do
543        // not want the class loader to return app's custom views.
544        // This is so that the IDE can instantiate the custom views and also generate proper error
545        // messages in case of failure. This also enables the IDE to fallback to MockView in case
546        // there's an exception thrown when trying to inflate the custom view.
547        // To work around this issue, LayoutInflater is modified via LayoutLib Create tool to
548        // replace invocations of this method to a new method: getFrameworkClassLoader(). Also,
549        // the method is injected into Context. The implementation of getFrameworkClassLoader() is:
550        // "return getClass().getClassLoader();". This means that when LayoutInflater asks for
551        // the context ClassLoader, it gets only LayoutLib's ClassLoader which doesn't have
552        // access to the apps's custom views.
553        // This method can now return the right ClassLoader, which CustomViews can use to do the
554        // right thing.
555        if (mClassLoader == null) {
556            mClassLoader = new ClassLoader(getClass().getClassLoader()) {
557                @Override
558                protected Class<?> findClass(String name) throws ClassNotFoundException {
559                    for (String prefix : BridgeInflater.getClassPrefixList()) {
560                        if (name.startsWith(prefix)) {
561                            // These are framework classes and should not be loaded from the app.
562                            throw new ClassNotFoundException(name + " not found");
563                        }
564                    }
565                    return BridgeContext.this.mLayoutlibCallback.findClass(name);
566                }
567            };
568        }
569        return mClassLoader;
570    }
571
572    @Override
573    public Object getSystemService(String service) {
574        if (LAYOUT_INFLATER_SERVICE.equals(service)) {
575            return mBridgeInflater;
576        }
577
578        if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) {
579            // we need to return a valid service to avoid NPE
580            return TextServicesManager.getInstance();
581        }
582
583        if (WINDOW_SERVICE.equals(service)) {
584            return mWindowManager;
585        }
586
587        // needed by SearchView
588        if (INPUT_METHOD_SERVICE.equals(service)) {
589            return null;
590        }
591
592        if (POWER_SERVICE.equals(service)) {
593            return new PowerManager(this, new BridgePowerManager(), new Handler());
594        }
595
596        if (DISPLAY_SERVICE.equals(service)) {
597            return mDisplayManager;
598        }
599
600        if (ACCESSIBILITY_SERVICE.equals(service)) {
601            return AccessibilityManager.getInstance(this);
602        }
603
604        throw new UnsupportedOperationException("Unsupported Service: " + service);
605    }
606
607    @Override
608    public String getSystemServiceName(Class<?> serviceClass) {
609        if (serviceClass.equals(LayoutInflater.class)) {
610            return LAYOUT_INFLATER_SERVICE;
611        }
612
613        if (serviceClass.equals(TextServicesManager.class)) {
614            return TEXT_SERVICES_MANAGER_SERVICE;
615        }
616
617        if (serviceClass.equals(WindowManager.class)) {
618            return WINDOW_SERVICE;
619        }
620
621        if (serviceClass.equals(PowerManager.class)) {
622            return POWER_SERVICE;
623        }
624
625        if (serviceClass.equals(DisplayManager.class)) {
626            return DISPLAY_SERVICE;
627        }
628
629        if (serviceClass.equals(AccessibilityManager.class)) {
630            return ACCESSIBILITY_SERVICE;
631        }
632
633        throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
634    }
635
636    @Override
637    public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
638        return obtainStyledAttributes(0, attrs);
639    }
640
641    @Override
642    public final BridgeTypedArray obtainStyledAttributes(int resId, int[] attrs)
643            throws Resources.NotFoundException {
644        StyleResourceValue style = null;
645        // get the StyleResourceValue based on the resId;
646        if (resId != 0) {
647            style = getStyleByDynamicId(resId);
648
649            if (style == null) {
650                // In some cases, style may not be a dynamic id, so we do a full search.
651                ResourceReference ref = resolveId(resId);
652                if (ref != null) {
653                    style = mRenderResources.getStyle(ref.getName(), ref.isFramework());
654                }
655            }
656
657            if (style == null) {
658                throw new Resources.NotFoundException();
659            }
660        }
661
662        if (mTypedArrayCache == null) {
663            mTypedArrayCache = new TypedArrayCache();
664        }
665
666        List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
667
668        Pair<BridgeTypedArray, PropertiesMap> typeArrayAndPropertiesPair =
669                mTypedArrayCache.get(attrs, currentThemes, resId);
670
671        if (typeArrayAndPropertiesPair == null) {
672            typeArrayAndPropertiesPair = createStyleBasedTypedArray(style, attrs);
673            mTypedArrayCache.put(attrs, currentThemes, resId, typeArrayAndPropertiesPair);
674        }
675        // Add value to defaultPropsMap if needed
676        if (typeArrayAndPropertiesPair.getSecond() != null) {
677            BridgeXmlBlockParser parser = getCurrentParser();
678            Object key = parser != null ? parser.getViewCookie() : null;
679            if (key != null) {
680                PropertiesMap defaultPropMap = mDefaultPropMaps.get(key);
681                if (defaultPropMap == null) {
682                    defaultPropMap = typeArrayAndPropertiesPair.getSecond();
683                    mDefaultPropMaps.put(key, defaultPropMap);
684                } else {
685                    defaultPropMap.putAll(typeArrayAndPropertiesPair.getSecond());
686                }
687            }
688        }
689        return typeArrayAndPropertiesPair.getFirst();
690    }
691
692    @Override
693    public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
694        return obtainStyledAttributes(set, attrs, 0, 0);
695    }
696
697    @Override
698    public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
699            int defStyleAttr, int defStyleRes) {
700
701        PropertiesMap defaultPropMap = null;
702        boolean isPlatformFile = true;
703
704        // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
705        if (set instanceof BridgeXmlBlockParser) {
706            BridgeXmlBlockParser parser;
707            parser = (BridgeXmlBlockParser)set;
708
709            isPlatformFile = parser.isPlatformFile();
710
711            Object key = parser.getViewCookie();
712            if (key != null) {
713                defaultPropMap = mDefaultPropMaps.get(key);
714                if (defaultPropMap == null) {
715                    defaultPropMap = new PropertiesMap();
716                    mDefaultPropMaps.put(key, defaultPropMap);
717                }
718            }
719
720        } else if (set instanceof BridgeLayoutParamsMapAttributes) {
721            // this is only for temp layout params generated dynamically, so this is never
722            // platform content.
723            isPlatformFile = false;
724        } else if (set != null) { // null parser is ok
725            // really this should not be happening since its instantiated in Bridge
726            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
727                    "Parser is not a BridgeXmlBlockParser!", null);
728            return null;
729        }
730
731        List<Pair<String, Boolean>> attributeList = searchAttrs(attrs);
732
733        BridgeTypedArray ta =
734                Resources_Delegate.newTypeArray(mSystemResources, attrs.length, isPlatformFile);
735
736        // look for a custom style.
737        String customStyle = null;
738        if (set != null) {
739            customStyle = set.getAttributeValue(null, "style");
740        }
741
742        StyleResourceValue customStyleValues = null;
743        if (customStyle != null) {
744            ResourceValue item = mRenderResources.findResValue(customStyle,
745                    isPlatformFile /*forceFrameworkOnly*/);
746
747            // resolve it in case it links to something else
748            item = mRenderResources.resolveResValue(item);
749
750            if (item instanceof StyleResourceValue) {
751                customStyleValues = (StyleResourceValue)item;
752            }
753        }
754
755        // resolve the defStyleAttr value into a IStyleResourceValue
756        StyleResourceValue defStyleValues = null;
757
758        if (defStyleAttr != 0) {
759            // get the name from the int.
760            Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
761
762            if (defStyleAttribute == null) {
763                // This should be rare. Happens trying to map R.style.foo to @style/foo fails.
764                // This will happen if the user explicitly used a non existing int value for
765                // defStyleAttr or there's something wrong with the project structure/build.
766                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
767                        "Failed to find the style corresponding to the id " + defStyleAttr, null);
768            } else {
769                String defStyleName = defStyleAttribute.getFirst();
770
771                // look for the style in the current theme, and its parent:
772                ResourceValue item = mRenderResources.findItemInTheme(defStyleName,
773                        defStyleAttribute.getSecond());
774
775                if (item != null) {
776                    // item is a reference to a style entry. Search for it.
777                    item = mRenderResources.findResValue(item.getValue(), item.isFramework());
778                    item = mRenderResources.resolveResValue(item);
779                    if (item instanceof StyleResourceValue) {
780                        defStyleValues = (StyleResourceValue) item;
781                    }
782                    if (defaultPropMap != null) {
783                        if (defStyleAttribute.getSecond()) {
784                            defStyleName = "android:" + defStyleName;
785                        }
786                        defaultPropMap.put("style", new Property(defStyleName, item.getValue()));
787                    }
788                } else {
789                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
790                            String.format(
791                                    "Failed to find style '%s' in current theme",
792                                    defStyleAttribute.getFirst()),
793                            null);
794                }
795            }
796        } else if (defStyleRes != 0) {
797            StyleResourceValue item = getStyleByDynamicId(defStyleRes);
798            if (item != null) {
799                defStyleValues = item;
800            } else {
801                boolean isFrameworkRes = true;
802                Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
803                if (value == null) {
804                    value = mLayoutlibCallback.resolveResourceId(defStyleRes);
805                    isFrameworkRes = false;
806                }
807
808                if (value != null) {
809                    if ((value.getFirst() == ResourceType.STYLE)) {
810                        // look for the style in all resources:
811                        item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes);
812                        if (item != null) {
813                            if (defaultPropMap != null) {
814                                String name = item.getName();
815                                defaultPropMap.put("style", new Property(name, name));
816                            }
817
818                            defStyleValues = item;
819                        } else {
820                            Bridge.getLog().error(null,
821                                    String.format(
822                                            "Style with id 0x%x (resolved to '%s') does not exist.",
823                                            defStyleRes, value.getSecond()),
824                                    null);
825                        }
826                    } else {
827                        Bridge.getLog().error(null,
828                                String.format(
829                                        "Resource id 0x%x is not of type STYLE (instead %s)",
830                                        defStyleRes, value.getFirst().toString()),
831                                null);
832                    }
833                } else {
834                    Bridge.getLog().error(null,
835                            String.format(
836                                    "Failed to find style with id 0x%x in current theme",
837                                    defStyleRes),
838                            null);
839                }
840            }
841        }
842
843        String appNamespace = mLayoutlibCallback.getNamespace();
844
845        if (attributeList != null) {
846            for (int index = 0 ; index < attributeList.size() ; index++) {
847                Pair<String, Boolean> attribute = attributeList.get(index);
848
849                if (attribute == null) {
850                    continue;
851                }
852
853                String attrName = attribute.getFirst();
854                boolean frameworkAttr = attribute.getSecond();
855                String value = null;
856                if (set != null) {
857                    value = set.getAttributeValue(
858                            frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace,
859                                    attrName);
860
861                    // if this is an app attribute, and the first get fails, try with the
862                    // new res-auto namespace as well
863                    if (!frameworkAttr && value == null) {
864                        value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
865                    }
866                }
867
868                // Calculate the default value from the Theme in two cases:
869                //   - If defaultPropMap is not null, get the default value to add it to the list
870                //   of default values of properties.
871                //   - If value is null, it means that the attribute is not directly set as an
872                //   attribute in the XML so try to get the default value.
873                ResourceValue defaultValue = null;
874                if (defaultPropMap != null || value == null) {
875                    // look for the value in the custom style first (and its parent if needed)
876                    if (customStyleValues != null) {
877                        defaultValue = mRenderResources.findItemInStyle(customStyleValues, attrName,
878                                frameworkAttr);
879                    }
880
881                    // then look for the value in the default Style (and its parent if needed)
882                    if (defaultValue == null && defStyleValues != null) {
883                        defaultValue = mRenderResources.findItemInStyle(defStyleValues, attrName,
884                                frameworkAttr);
885                    }
886
887                    // if the item is not present in the defStyle, we look in the main theme (and
888                    // its parent themes)
889                    if (defaultValue == null) {
890                        defaultValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
891                    }
892
893                    // if we found a value, we make sure this doesn't reference another value.
894                    // So we resolve it.
895                    if (defaultValue != null) {
896                        String preResolve = defaultValue.getValue();
897                        defaultValue = mRenderResources.resolveResValue(defaultValue);
898
899                        if (defaultPropMap != null) {
900                            defaultPropMap.put(
901                                    frameworkAttr ? SdkConstants.PREFIX_ANDROID + attrName :
902                                            attrName, new Property(preResolve, defaultValue.getValue()));
903                        }
904                    }
905                }
906                // Done calculating the defaultValue
907
908                // if there's no direct value for this attribute in the XML, we look for default
909                // values in the widget defStyle, and then in the theme.
910                if (value == null) {
911                    // if we found a value, we make sure this doesn't reference another value.
912                    // So we resolve it.
913                    if (defaultValue != null) {
914                        // If the value is a reference to another theme attribute that doesn't
915                        // exist, we should log a warning and omit it.
916                        String val = defaultValue.getValue();
917                        if (val != null && val.startsWith(SdkConstants.PREFIX_THEME_REF)) {
918                            if (!attrName.equals(RTL_ATTRS.get(val)) ||
919                                    getApplicationInfo().targetSdkVersion <
920                                            VERSION_CODES.JELLY_BEAN_MR1) {
921                                // Only log a warning if the referenced value isn't one of the RTL
922                                // attributes, or the app targets old API.
923                                Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
924                                        String.format("Failed to find '%s' in current theme.", val),
925                                        val);
926                            }
927                            defaultValue = null;
928                        }
929                    }
930
931                    ta.bridgeSetValue(index, attrName, frameworkAttr, defaultValue);
932                } else {
933                    // there is a value in the XML, but we need to resolve it in case it's
934                    // referencing another resource or a theme value.
935                    ta.bridgeSetValue(index, attrName, frameworkAttr,
936                            mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
937                }
938            }
939        }
940
941        ta.sealArray();
942
943        return ta;
944    }
945
946    @Override
947    public Looper getMainLooper() {
948        return Looper.myLooper();
949    }
950
951
952    @Override
953    public String getPackageName() {
954        if (mApplicationInfo.packageName == null) {
955            mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE);
956        }
957        return mApplicationInfo.packageName;
958    }
959
960    @Override
961    public PackageManager getPackageManager() {
962        if (mPackageManager == null) {
963            mPackageManager = new BridgePackageManager();
964        }
965        return mPackageManager;
966    }
967
968    // ------------- private new methods
969
970    /**
971     * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
972     * values found in the given style. If no style is specified, the default theme, along with the
973     * styles applied to it are used.
974     *
975     * @see #obtainStyledAttributes(int, int[])
976     */
977    private Pair<BridgeTypedArray, PropertiesMap> createStyleBasedTypedArray(
978            @Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException {
979        List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
980
981        BridgeTypedArray ta =
982                Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false);
983
984        PropertiesMap defaultPropMap = new PropertiesMap();
985        // for each attribute, get its name so that we can search it in the style
986        for (int i = 0; i < attrs.length; i++) {
987            Pair<String, Boolean> attribute = attributes.get(i);
988
989            if (attribute != null) {
990                // look for the value in the given style
991                ResourceValue resValue;
992                String attrName = attribute.getFirst();
993                boolean frameworkAttr = attribute.getSecond();
994                if (style != null) {
995                    resValue = mRenderResources.findItemInStyle(style, attrName, frameworkAttr);
996                } else {
997                    resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
998                }
999
1000                if (resValue != null) {
1001                    // Add it to defaultPropMap before resolving
1002                    String preResolve = resValue.getValue();
1003                    // resolve it to make sure there are no references left.
1004                    resValue = mRenderResources.resolveResValue(resValue);
1005                    ta.bridgeSetValue(i, attrName, frameworkAttr, resValue);
1006                    defaultPropMap.put(
1007                            frameworkAttr ? SdkConstants.ANDROID_PREFIX + attrName : attrName,
1008                            new Property(preResolve, resValue.getValue()));
1009                }
1010            }
1011        }
1012
1013        ta.sealArray();
1014
1015        return Pair.of(ta, defaultPropMap);
1016    }
1017
1018    /**
1019     * The input int[] attrs is a list of attributes. The returns a list of information about
1020     * each attributes. The information is (name, isFramework)
1021     * <p/>
1022     *
1023     * @param attrs An attribute array reference given to obtainStyledAttributes.
1024     * @return List of attribute information.
1025     */
1026    private List<Pair<String, Boolean>> searchAttrs(int[] attrs) {
1027        List<Pair<String, Boolean>> results = new ArrayList<>(attrs.length);
1028
1029        // for each attribute, get its name so that we can search it in the style
1030        for (int attr : attrs) {
1031            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr);
1032            boolean isFramework = false;
1033            if (resolvedResource != null) {
1034                isFramework = true;
1035            } else {
1036                resolvedResource = mLayoutlibCallback.resolveResourceId(attr);
1037            }
1038
1039            if (resolvedResource != null) {
1040                results.add(Pair.of(resolvedResource.getSecond(), isFramework));
1041            } else {
1042                results.add(null);
1043            }
1044        }
1045
1046        return results;
1047    }
1048
1049    /**
1050     * Searches for the attribute referenced by its internal id.
1051     *
1052     * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
1053     * @return A (name, isFramework) pair describing the attribute if found. Returns null
1054     *         if nothing is found.
1055     */
1056    private Pair<String, Boolean> searchAttr(int attr) {
1057        Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
1058        if (info != null) {
1059            return Pair.of(info.getSecond(), Boolean.TRUE);
1060        }
1061
1062        info = mLayoutlibCallback.resolveResourceId(attr);
1063        if (info != null) {
1064            return Pair.of(info.getSecond(), Boolean.FALSE);
1065        }
1066
1067        return null;
1068    }
1069
1070    public int getDynamicIdByStyle(StyleResourceValue resValue) {
1071        if (mDynamicIdToStyleMap == null) {
1072            // create the maps.
1073            mDynamicIdToStyleMap = new HashMap<>();
1074            mStyleToDynamicIdMap = new HashMap<>();
1075        }
1076
1077        // look for an existing id
1078        Integer id = mStyleToDynamicIdMap.get(resValue);
1079
1080        if (id == null) {
1081            // generate a new id
1082            id = ++mDynamicIdGenerator;
1083
1084            // and add it to the maps.
1085            mDynamicIdToStyleMap.put(id, resValue);
1086            mStyleToDynamicIdMap.put(resValue, id);
1087        }
1088
1089        return id;
1090    }
1091
1092    private StyleResourceValue getStyleByDynamicId(int i) {
1093        if (mDynamicIdToStyleMap != null) {
1094            return mDynamicIdToStyleMap.get(i);
1095        }
1096
1097        return null;
1098    }
1099
1100    public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
1101        if (getRenderResources().getFrameworkResource(resType, resName) != null) {
1102            // Bridge.getResourceId creates a new resource id if an existing one isn't found. So,
1103            // we check for the existence of the resource before calling it.
1104            return Bridge.getResourceId(resType, resName);
1105        }
1106
1107        return defValue;
1108    }
1109
1110    public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
1111        // getResourceId creates a new resource id if an existing resource id isn't found. So, we
1112        // check for the existence of the resource before calling it.
1113        if (getRenderResources().getProjectResource(resType, resName) != null) {
1114            if (mLayoutlibCallback != null) {
1115                Integer value = mLayoutlibCallback.getResourceId(resType, resName);
1116                if (value != null) {
1117                    return value;
1118                }
1119            }
1120        }
1121
1122        return defValue;
1123    }
1124
1125    public static Context getBaseContext(Context context) {
1126        while (context instanceof ContextWrapper) {
1127            context = ((ContextWrapper) context).getBaseContext();
1128        }
1129        return context;
1130    }
1131
1132    public IBinder getBinder() {
1133        if (mBinder == null) {
1134            // create a dummy binder. We only need it be not null.
1135            mBinder = new IBinder() {
1136                @Override
1137                public String getInterfaceDescriptor() throws RemoteException {
1138                    return null;
1139                }
1140
1141                @Override
1142                public boolean pingBinder() {
1143                    return false;
1144                }
1145
1146                @Override
1147                public boolean isBinderAlive() {
1148                    return false;
1149                }
1150
1151                @Override
1152                public IInterface queryLocalInterface(String descriptor) {
1153                    return null;
1154                }
1155
1156                @Override
1157                public void dump(FileDescriptor fd, String[] args) throws RemoteException {
1158
1159                }
1160
1161                @Override
1162                public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
1163
1164                }
1165
1166                @Override
1167                public boolean transact(int code, Parcel data, Parcel reply, int flags)
1168                        throws RemoteException {
1169                    return false;
1170                }
1171
1172                @Override
1173                public void linkToDeath(DeathRecipient recipient, int flags)
1174                        throws RemoteException {
1175
1176                }
1177
1178                @Override
1179                public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
1180                    return false;
1181                }
1182
1183                @Override
1184                public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1185                  String[] args, ResultReceiver resultReceiver) {
1186                }
1187            };
1188        }
1189        return mBinder;
1190    }
1191
1192    //------------ NOT OVERRIDEN --------------------
1193
1194    @Override
1195    public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
1196        // pass
1197        return false;
1198    }
1199
1200    @Override
1201    public int checkCallingOrSelfPermission(String arg0) {
1202        // pass
1203        return 0;
1204    }
1205
1206    @Override
1207    public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
1208        // pass
1209        return 0;
1210    }
1211
1212    @Override
1213    public int checkCallingPermission(String arg0) {
1214        // pass
1215        return 0;
1216    }
1217
1218    @Override
1219    public int checkCallingUriPermission(Uri arg0, int arg1) {
1220        // pass
1221        return 0;
1222    }
1223
1224    @Override
1225    public int checkPermission(String arg0, int arg1, int arg2) {
1226        // pass
1227        return 0;
1228    }
1229
1230    @Override
1231    public int checkSelfPermission(String arg0) {
1232        // pass
1233        return 0;
1234    }
1235
1236    @Override
1237    public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
1238        // pass
1239        return 0;
1240    }
1241
1242    @Override
1243    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
1244        // pass
1245        return 0;
1246    }
1247
1248    @Override
1249    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) {
1250        // pass
1251        return 0;
1252    }
1253
1254    @Override
1255    public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
1256            int arg4, int arg5) {
1257        // pass
1258        return 0;
1259    }
1260
1261    @Override
1262    public void clearWallpaper() {
1263        // pass
1264
1265    }
1266
1267    @Override
1268    public Context createPackageContext(String arg0, int arg1) {
1269        // pass
1270        return null;
1271    }
1272
1273    @Override
1274    public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
1275        // pass
1276        return null;
1277    }
1278
1279    @Override
1280    public Context createConfigurationContext(Configuration overrideConfiguration) {
1281        // pass
1282        return null;
1283    }
1284
1285    @Override
1286    public Context createDisplayContext(Display display) {
1287        // pass
1288        return null;
1289    }
1290
1291    @Override
1292    public String[] databaseList() {
1293        // pass
1294        return null;
1295    }
1296
1297    @Override
1298    public Context createApplicationContext(ApplicationInfo application, int flags)
1299            throws PackageManager.NameNotFoundException {
1300        return null;
1301    }
1302
1303    @Override
1304    public boolean moveDatabaseFrom(Context sourceContext, String name) {
1305        // pass
1306        return false;
1307    }
1308
1309    @Override
1310    public boolean deleteDatabase(String arg0) {
1311        // pass
1312        return false;
1313    }
1314
1315    @Override
1316    public boolean deleteFile(String arg0) {
1317        // pass
1318        return false;
1319    }
1320
1321    @Override
1322    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
1323        // pass
1324
1325    }
1326
1327    @Override
1328    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
1329            String arg2) {
1330        // pass
1331
1332    }
1333
1334    @Override
1335    public void enforceCallingPermission(String arg0, String arg1) {
1336        // pass
1337
1338    }
1339
1340    @Override
1341    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
1342        // pass
1343
1344    }
1345
1346    @Override
1347    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
1348        // pass
1349
1350    }
1351
1352    @Override
1353    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
1354            String arg4) {
1355        // pass
1356
1357    }
1358
1359    @Override
1360    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
1361            int arg3, int arg4, int arg5, String arg6) {
1362        // pass
1363
1364    }
1365
1366    @Override
1367    public String[] fileList() {
1368        // pass
1369        return null;
1370    }
1371
1372    @Override
1373    public BridgeAssetManager getAssets() {
1374        return mAssets;
1375    }
1376
1377    @Override
1378    public File getCacheDir() {
1379        // pass
1380        return null;
1381    }
1382
1383    @Override
1384    public File getCodeCacheDir() {
1385        // pass
1386        return null;
1387    }
1388
1389    @Override
1390    public File getExternalCacheDir() {
1391        // pass
1392        return null;
1393    }
1394
1395    @Override
1396    public ContentResolver getContentResolver() {
1397        if (mContentResolver == null) {
1398            mContentResolver = new BridgeContentResolver(this);
1399        }
1400        return mContentResolver;
1401    }
1402
1403    @Override
1404    public File getDatabasePath(String arg0) {
1405        // pass
1406        return null;
1407    }
1408
1409    @Override
1410    public File getDir(String arg0, int arg1) {
1411        // pass
1412        return null;
1413    }
1414
1415    @Override
1416    public File getFileStreamPath(String arg0) {
1417        // pass
1418        return null;
1419    }
1420
1421    @Override
1422    public File getSharedPreferencesPath(String name) {
1423        // pass
1424        return null;
1425    }
1426
1427    @Override
1428    public File getDataDir() {
1429        // pass
1430        return null;
1431    }
1432
1433    @Override
1434    public File getFilesDir() {
1435        // pass
1436        return null;
1437    }
1438
1439    @Override
1440    public File getNoBackupFilesDir() {
1441        // pass
1442        return null;
1443    }
1444
1445    @Override
1446    public File getExternalFilesDir(String type) {
1447        // pass
1448        return null;
1449    }
1450
1451    @Override
1452    public String getPackageCodePath() {
1453        // pass
1454        return null;
1455    }
1456
1457    @Override
1458    public String getBasePackageName() {
1459        // pass
1460        return null;
1461    }
1462
1463    @Override
1464    public String getOpPackageName() {
1465        // pass
1466        return null;
1467    }
1468
1469    @Override
1470    public ApplicationInfo getApplicationInfo() {
1471        return mApplicationInfo;
1472    }
1473
1474    @Override
1475    public String getPackageResourcePath() {
1476        // pass
1477        return null;
1478    }
1479
1480    @Override
1481    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1482        if (mSharedPreferences == null) {
1483            mSharedPreferences = new BridgeSharedPreferences();
1484        }
1485        return mSharedPreferences;
1486    }
1487
1488    @Override
1489    public SharedPreferences getSharedPreferences(File arg0, int arg1) {
1490        if (mSharedPreferences == null) {
1491            mSharedPreferences = new BridgeSharedPreferences();
1492        }
1493        return mSharedPreferences;
1494    }
1495
1496    @Override
1497    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
1498        // pass
1499        return false;
1500    }
1501
1502    @Override
1503    public boolean deleteSharedPreferences(String name) {
1504        // pass
1505        return false;
1506    }
1507
1508    @Override
1509    public Drawable getWallpaper() {
1510        // pass
1511        return null;
1512    }
1513
1514    @Override
1515    public int getWallpaperDesiredMinimumWidth() {
1516        return -1;
1517    }
1518
1519    @Override
1520    public int getWallpaperDesiredMinimumHeight() {
1521        return -1;
1522    }
1523
1524    @Override
1525    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1526        // pass
1527
1528    }
1529
1530    @Override
1531    public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1532        // pass
1533        return null;
1534    }
1535
1536    @Override
1537    public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1538        // pass
1539        return null;
1540    }
1541
1542    @Override
1543    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1544        // pass
1545        return null;
1546    }
1547
1548    @Override
1549    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1550            CursorFactory arg2, DatabaseErrorHandler arg3) {
1551        // pass
1552        return null;
1553    }
1554
1555    @Override
1556    public Drawable peekWallpaper() {
1557        // pass
1558        return null;
1559    }
1560
1561    @Override
1562    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1563        // pass
1564        return null;
1565    }
1566
1567    @Override
1568    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1569            String arg2, Handler arg3) {
1570        // pass
1571        return null;
1572    }
1573
1574    @Override
1575    public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
1576            IntentFilter arg1, String arg2, Handler arg3) {
1577        // pass
1578        return null;
1579    }
1580
1581    @Override
1582    public void removeStickyBroadcast(Intent arg0) {
1583        // pass
1584
1585    }
1586
1587    @Override
1588    public void revokeUriPermission(Uri arg0, int arg1) {
1589        // pass
1590
1591    }
1592
1593    @Override
1594    public void sendBroadcast(Intent arg0) {
1595        // pass
1596
1597    }
1598
1599    @Override
1600    public void sendBroadcast(Intent arg0, String arg1) {
1601        // pass
1602
1603    }
1604
1605    @Override
1606    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
1607        // pass
1608
1609    }
1610
1611    @Override
1612    public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) {
1613        // pass
1614
1615    }
1616
1617    @Override
1618    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
1619        // pass
1620    }
1621
1622    @Override
1623    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1624        // pass
1625
1626    }
1627
1628    @Override
1629    public void sendOrderedBroadcast(Intent arg0, String arg1,
1630            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1631            Bundle arg6) {
1632        // pass
1633
1634    }
1635
1636    @Override
1637    public void sendOrderedBroadcast(Intent arg0, String arg1,
1638            Bundle arg7, BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1639            Bundle arg6) {
1640        // pass
1641
1642    }
1643
1644    @Override
1645    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
1646            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
1647            String initialData, Bundle initialExtras) {
1648        // pass
1649    }
1650
1651    @Override
1652    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
1653        // pass
1654    }
1655
1656    @Override
1657    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1658            String receiverPermission) {
1659        // pass
1660    }
1661
1662    @Override
1663    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1664            String receiverPermission, Bundle options) {
1665        // pass
1666    }
1667
1668    public void sendBroadcastAsUser(Intent intent, UserHandle user,
1669            String receiverPermission, int appOp) {
1670        // pass
1671    }
1672
1673    @Override
1674    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1675            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
1676            int initialCode, String initialData, Bundle initialExtras) {
1677        // pass
1678    }
1679
1680    @Override
1681    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1682            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
1683            Handler scheduler,
1684            int initialCode, String initialData, Bundle initialExtras) {
1685        // pass
1686    }
1687
1688    @Override
1689    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
1690            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
1691            Handler scheduler,
1692            int initialCode, String initialData, Bundle initialExtras) {
1693        // pass
1694    }
1695
1696    @Override
1697    public void sendStickyBroadcast(Intent arg0) {
1698        // pass
1699
1700    }
1701
1702    @Override
1703    public void sendStickyOrderedBroadcast(Intent intent,
1704            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1705           Bundle initialExtras) {
1706        // pass
1707    }
1708
1709    @Override
1710    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
1711        // pass
1712    }
1713
1714    @Override
1715    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
1716        // pass
1717    }
1718
1719    @Override
1720    public void sendStickyOrderedBroadcastAsUser(Intent intent,
1721            UserHandle user, BroadcastReceiver resultReceiver,
1722            Handler scheduler, int initialCode, String initialData,
1723            Bundle initialExtras) {
1724        // pass
1725    }
1726
1727    @Override
1728    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
1729        // pass
1730    }
1731
1732    @Override
1733    public void setTheme(int arg0) {
1734        // pass
1735
1736    }
1737
1738    @Override
1739    public void setWallpaper(Bitmap arg0) throws IOException {
1740        // pass
1741
1742    }
1743
1744    @Override
1745    public void setWallpaper(InputStream arg0) throws IOException {
1746        // pass
1747
1748    }
1749
1750    @Override
1751    public void startActivity(Intent arg0) {
1752        // pass
1753    }
1754
1755    @Override
1756    public void startActivity(Intent arg0, Bundle arg1) {
1757        // pass
1758    }
1759
1760    @Override
1761    public void startIntentSender(IntentSender intent,
1762            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1763            throws IntentSender.SendIntentException {
1764        // pass
1765    }
1766
1767    @Override
1768    public void startIntentSender(IntentSender intent,
1769            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1770            Bundle options) throws IntentSender.SendIntentException {
1771        // pass
1772    }
1773
1774    @Override
1775    public boolean startInstrumentation(ComponentName arg0, String arg1,
1776            Bundle arg2) {
1777        // pass
1778        return false;
1779    }
1780
1781    @Override
1782    public ComponentName startService(Intent arg0) {
1783        // pass
1784        return null;
1785    }
1786
1787    @Override
1788    public boolean stopService(Intent arg0) {
1789        // pass
1790        return false;
1791    }
1792
1793    @Override
1794    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
1795        // pass
1796        return null;
1797    }
1798
1799    @Override
1800    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
1801        // pass
1802        return false;
1803    }
1804
1805    @Override
1806    public void unbindService(ServiceConnection arg0) {
1807        // pass
1808
1809    }
1810
1811    @Override
1812    public void unregisterReceiver(BroadcastReceiver arg0) {
1813        // pass
1814
1815    }
1816
1817    @Override
1818    public Context getApplicationContext() {
1819        return this;
1820    }
1821
1822    @Override
1823    public void startActivities(Intent[] arg0) {
1824        // pass
1825
1826    }
1827
1828    @Override
1829    public void startActivities(Intent[] arg0, Bundle arg1) {
1830        // pass
1831
1832    }
1833
1834    @Override
1835    public boolean isRestricted() {
1836        return false;
1837    }
1838
1839    @Override
1840    public File getObbDir() {
1841        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1842        return null;
1843    }
1844
1845    @Override
1846    public DisplayAdjustments getDisplayAdjustments(int displayId) {
1847        // pass
1848        return null;
1849    }
1850
1851    @Override
1852    public Display getDisplay() {
1853        // pass
1854        return null;
1855    }
1856
1857    @Override
1858    public int getUserId() {
1859        return 0; // not used
1860    }
1861
1862    @Override
1863    public File[] getExternalFilesDirs(String type) {
1864        // pass
1865        return new File[0];
1866    }
1867
1868    @Override
1869    public File[] getObbDirs() {
1870        // pass
1871        return new File[0];
1872    }
1873
1874    @Override
1875    public File[] getExternalCacheDirs() {
1876        // pass
1877        return new File[0];
1878    }
1879
1880    @Override
1881    public File[] getExternalMediaDirs() {
1882        // pass
1883        return new File[0];
1884    }
1885
1886    public void setScrollYPos(@NonNull View view, int scrollPos) {
1887        mScrollYPos.put(view, scrollPos);
1888    }
1889
1890    public int getScrollYPos(@NonNull View view) {
1891        Integer pos = mScrollYPos.get(view);
1892        return pos != null ? pos : 0;
1893    }
1894
1895    public void setScrollXPos(@NonNull View view, int scrollPos) {
1896        mScrollXPos.put(view, scrollPos);
1897    }
1898
1899    public int getScrollXPos(@NonNull View view) {
1900        Integer pos = mScrollXPos.get(view);
1901        return pos != null ? pos : 0;
1902    }
1903
1904    @Override
1905    public Context createDeviceProtectedStorageContext() {
1906        // pass
1907        return null;
1908    }
1909
1910    @Override
1911    public Context createCredentialProtectedStorageContext() {
1912        // pass
1913        return null;
1914    }
1915
1916    @Override
1917    public boolean isDeviceProtectedStorage() {
1918        return false;
1919    }
1920
1921    @Override
1922    public boolean isCredentialProtectedStorage() {
1923        return false;
1924    }
1925
1926    /**
1927     * The cached value depends on
1928     * <ol>
1929     * <li>{@code int[]}: the attributes for which TypedArray is created </li>
1930     * <li>{@code List<StyleResourceValue>}: the themes set on the context at the time of
1931     * creation of the TypedArray</li>
1932     * <li>{@code Integer}: the default style used at the time of creation</li>
1933     * </ol>
1934     *
1935     * The class is created by using nested maps resolving one dependency at a time.
1936     * <p/>
1937     * The final value of the nested maps is a pair of the typed array and a map of properties
1938     * that should be added to {@link #mDefaultPropMaps}, if needed.
1939     */
1940    private static class TypedArrayCache {
1941
1942        private Map<int[],
1943                Map<List<StyleResourceValue>,
1944                        Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>> mCache;
1945
1946        public TypedArrayCache() {
1947            mCache = new IdentityHashMap<>();
1948        }
1949
1950        public Pair<BridgeTypedArray, PropertiesMap> get(int[] attrs,
1951                List<StyleResourceValue> themes, int resId) {
1952            Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
1953                    cacheFromThemes = mCache.get(attrs);
1954            if (cacheFromThemes != null) {
1955                Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
1956                        cacheFromThemes.get(themes);
1957                if (cacheFromResId != null) {
1958                    return cacheFromResId.get(resId);
1959                }
1960            }
1961            return null;
1962        }
1963
1964        public void put(int[] attrs, List<StyleResourceValue> themes, int resId,
1965                Pair<BridgeTypedArray, PropertiesMap> value) {
1966            Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
1967                    cacheFromThemes = mCache.get(attrs);
1968            if (cacheFromThemes == null) {
1969                cacheFromThemes = new HashMap<>();
1970                mCache.put(attrs, cacheFromThemes);
1971            }
1972            Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
1973                    cacheFromThemes.get(themes);
1974            if (cacheFromResId == null) {
1975                cacheFromResId = new HashMap<>();
1976                cacheFromThemes.put(themes, cacheFromResId);
1977            }
1978            cacheFromResId.put(resId, value);
1979        }
1980
1981    }
1982}
1983