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