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