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