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.app.SystemServiceRegistry_Accessor; 45import android.content.BroadcastReceiver; 46import android.content.ComponentName; 47import android.content.ContentResolver; 48import android.content.Context; 49import android.content.ContextWrapper; 50import android.content.Intent; 51import android.content.IntentFilter; 52import android.content.IntentSender; 53import android.content.ServiceConnection; 54import android.content.SharedPreferences; 55import android.content.pm.ApplicationInfo; 56import android.content.pm.PackageManager; 57import android.content.res.AssetManager; 58import android.content.res.BridgeAssetManager; 59import android.content.res.BridgeTypedArray; 60import android.content.res.Configuration; 61import android.content.res.Resources; 62import android.content.res.Resources.Theme; 63import android.content.res.Resources_Delegate; 64import android.database.DatabaseErrorHandler; 65import android.database.sqlite.SQLiteDatabase; 66import android.database.sqlite.SQLiteDatabase.CursorFactory; 67import android.graphics.Bitmap; 68import android.graphics.Color; 69import android.graphics.drawable.Drawable; 70import android.hardware.display.DisplayManager; 71import android.net.Uri; 72import android.os.Bundle; 73import android.os.Handler; 74import android.os.IBinder; 75import android.os.IInterface; 76import android.os.Looper; 77import android.os.Parcel; 78import android.os.PowerManager; 79import android.os.RemoteException; 80import android.os.ResultReceiver; 81import android.os.ShellCallback; 82import android.os.UserHandle; 83import android.util.AttributeSet; 84import android.util.DisplayMetrics; 85import android.util.TypedValue; 86import android.view.BridgeInflater; 87import android.view.Display; 88import android.view.DisplayAdjustments; 89import android.view.LayoutInflater; 90import android.view.View; 91import android.view.ViewGroup; 92import android.view.WindowManager; 93import android.view.accessibility.AccessibilityManager; 94import android.view.textservice.TextServicesManager; 95 96import java.io.File; 97import java.io.FileDescriptor; 98import java.io.FileInputStream; 99import java.io.FileNotFoundException; 100import java.io.FileOutputStream; 101import java.io.IOException; 102import java.io.InputStream; 103import java.util.ArrayList; 104import java.util.HashMap; 105import java.util.IdentityHashMap; 106import java.util.List; 107import java.util.Map; 108 109import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1; 110import 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. 116public 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 */ 215 public BridgeContext(Object projectKey, DisplayMetrics metrics, 216 RenderResources renderResources, 217 AssetRepository assets, 218 LayoutlibCallback layoutlibCallback, 219 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 */ 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 */ 267 public void disposeResources() { 268 Resources_Delegate.disposeSystem(); 269 } 270 271 public void setBridgeInflater(BridgeInflater inflater) { 272 mBridgeInflater = inflater; 273 } 274 275 public void addViewKey(View view, Object viewKey) { 276 mViewKeyMap.put(view, viewKey); 277 } 278 279 public Object getViewKey(View view) { 280 return mViewKeyMap.get(view); 281 } 282 283 public void addCookie(Object o, Object cookie) { 284 mViewKeyHelpMap.put(o, cookie); 285 } 286 287 public Object getCookie(Object o) { 288 return mViewKeyHelpMap.get(o); 289 } 290 291 public Object getProjectKey() { 292 return mProjectKey; 293 } 294 295 public DisplayMetrics getMetrics() { 296 return mMetrics; 297 } 298 299 public LayoutlibCallback getLayoutlibCallback() { 300 return mLayoutlibCallback; 301 } 302 303 public RenderResources getRenderResources() { 304 return mRenderResources; 305 } 306 307 public Map<Object, PropertiesMap> getDefaultProperties() { 308 return mDefaultPropMaps; 309 } 310 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 */ 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 */ 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 */ 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 */ 348 public BridgeXmlBlockParser getPreviousParser() { 349 if (mParserStack.size() < 2) { 350 return null; 351 } 352 return mParserStack.get(mParserStack.size() - 2); 353 } 354 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 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 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 */ 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") 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 569 public Resources getResources() { 570 return mSystemResources; 571 } 572 573 @Override 574 public Theme getTheme() { 575 return mTheme; 576 } 577 578 @Override 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 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 656 public String getSystemServiceName(Class<?> serviceClass) { 657 return SystemServiceRegistry_Accessor.getSystemServiceName(serviceClass); 658 } 659 660 @Override 661 public final BridgeTypedArray obtainStyledAttributes(int[] attrs) { 662 return obtainStyledAttributes(0, attrs); 663 } 664 665 @Override 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 719 public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { 720 return obtainStyledAttributes(set, attrs, 0, 0); 721 } 722 723 @Override 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<Pair<String, Boolean>> 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 Pair<String, Boolean> attribute = attributeList.get(index); 870 871 if (attribute == null) { 872 continue; 873 } 874 875 String attrName = attribute.getFirst(); 876 boolean frameworkAttr = attribute.getSecond(); 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, defaultValue); 969 } else { 970 // there is a value in the XML, but we need to resolve it in case it's 971 // referencing another resource or a theme value. 972 ta.bridgeSetValue(index, attrName, frameworkAttr, 973 mRenderResources.resolveValue(null, attrName, value, isPlatformFile)); 974 } 975 } 976 } 977 978 ta.sealArray(); 979 980 return ta; 981 } 982 983 @Override 984 public Looper getMainLooper() { 985 return Looper.myLooper(); 986 } 987 988 989 @Override 990 public String getPackageName() { 991 if (mApplicationInfo.packageName == null) { 992 mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE); 993 } 994 return mApplicationInfo.packageName; 995 } 996 997 @Override 998 public PackageManager getPackageManager() { 999 if (mPackageManager == null) { 1000 mPackageManager = new BridgePackageManager(); 1001 } 1002 return mPackageManager; 1003 } 1004 1005 // ------------- private new methods 1006 1007 /** 1008 * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the 1009 * values found in the given style. If no style is specified, the default theme, along with the 1010 * styles applied to it are used. 1011 * 1012 * @see #obtainStyledAttributes(int, int[]) 1013 */ 1014 private Pair<BridgeTypedArray, PropertiesMap> createStyleBasedTypedArray( 1015 @Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException { 1016 List<Pair<String, Boolean>> attributes = searchAttrs(attrs); 1017 1018 BridgeTypedArray ta = 1019 Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false); 1020 1021 PropertiesMap defaultPropMap = new PropertiesMap(); 1022 // for each attribute, get its name so that we can search it in the style 1023 for (int i = 0; i < attrs.length; i++) { 1024 Pair<String, Boolean> attribute = attributes.get(i); 1025 1026 if (attribute != null) { 1027 // look for the value in the given style 1028 ResourceValue resValue; 1029 String attrName = attribute.getFirst(); 1030 boolean frameworkAttr = attribute.getSecond(); 1031 if (style != null) { 1032 resValue = mRenderResources.findItemInStyle(style, attrName, frameworkAttr); 1033 } else { 1034 resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr); 1035 } 1036 1037 if (resValue != null) { 1038 // Add it to defaultPropMap before resolving 1039 String preResolve = resValue.getValue(); 1040 // resolve it to make sure there are no references left. 1041 resValue = mRenderResources.resolveResValue(resValue); 1042 ta.bridgeSetValue(i, attrName, frameworkAttr, resValue); 1043 defaultPropMap.put( 1044 frameworkAttr ? SdkConstants.ANDROID_PREFIX + attrName : attrName, 1045 new Property(preResolve, resValue.getValue())); 1046 } 1047 } 1048 } 1049 1050 ta.sealArray(); 1051 1052 return Pair.of(ta, defaultPropMap); 1053 } 1054 1055 /** 1056 * The input int[] attrs is a list of attributes. The returns a list of information about 1057 * each attributes. The information is (name, isFramework) 1058 * <p/> 1059 * 1060 * @param attrs An attribute array reference given to obtainStyledAttributes. 1061 * @return List of attribute information. 1062 */ 1063 private List<Pair<String, Boolean>> searchAttrs(int[] attrs) { 1064 List<Pair<String, Boolean>> results = new ArrayList<>(attrs.length); 1065 1066 // for each attribute, get its name so that we can search it in the style 1067 for (int attr : attrs) { 1068 Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr); 1069 boolean isFramework = false; 1070 if (resolvedResource != null) { 1071 isFramework = true; 1072 } else { 1073 resolvedResource = mLayoutlibCallback.resolveResourceId(attr); 1074 } 1075 1076 if (resolvedResource != null) { 1077 results.add(Pair.of(resolvedResource.getSecond(), isFramework)); 1078 } else { 1079 results.add(null); 1080 } 1081 } 1082 1083 return results; 1084 } 1085 1086 /** 1087 * Searches for the attribute referenced by its internal id. 1088 * 1089 * @param attr An attribute reference given to obtainStyledAttributes such as defStyle. 1090 * @return A (name, isFramework) pair describing the attribute if found. Returns null 1091 * if nothing is found. 1092 */ 1093 private Pair<String, Boolean> searchAttr(int attr) { 1094 Pair<ResourceType, String> info = Bridge.resolveResourceId(attr); 1095 if (info != null) { 1096 return Pair.of(info.getSecond(), Boolean.TRUE); 1097 } 1098 1099 info = mLayoutlibCallback.resolveResourceId(attr); 1100 if (info != null) { 1101 return Pair.of(info.getSecond(), Boolean.FALSE); 1102 } 1103 1104 return null; 1105 } 1106 1107 public int getDynamicIdByStyle(StyleResourceValue resValue) { 1108 if (mDynamicIdToStyleMap == null) { 1109 // create the maps. 1110 mDynamicIdToStyleMap = new HashMap<>(); 1111 mStyleToDynamicIdMap = new HashMap<>(); 1112 } 1113 1114 // look for an existing id 1115 Integer id = mStyleToDynamicIdMap.get(resValue); 1116 1117 if (id == null) { 1118 // generate a new id 1119 id = ++mDynamicIdGenerator; 1120 1121 // and add it to the maps. 1122 mDynamicIdToStyleMap.put(id, resValue); 1123 mStyleToDynamicIdMap.put(resValue, id); 1124 } 1125 1126 return id; 1127 } 1128 1129 private StyleResourceValue getStyleByDynamicId(int i) { 1130 if (mDynamicIdToStyleMap != null) { 1131 return mDynamicIdToStyleMap.get(i); 1132 } 1133 1134 return null; 1135 } 1136 1137 public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) { 1138 if (getRenderResources().getFrameworkResource(resType, resName) != null) { 1139 // Bridge.getResourceId creates a new resource id if an existing one isn't found. So, 1140 // we check for the existence of the resource before calling it. 1141 return Bridge.getResourceId(resType, resName); 1142 } 1143 1144 return defValue; 1145 } 1146 1147 public int getProjectResourceValue(ResourceType resType, String resName, int defValue) { 1148 // getResourceId creates a new resource id if an existing resource id isn't found. So, we 1149 // check for the existence of the resource before calling it. 1150 if (getRenderResources().getProjectResource(resType, resName) != null) { 1151 if (mLayoutlibCallback != null) { 1152 Integer value = mLayoutlibCallback.getResourceId(resType, resName); 1153 if (value != null) { 1154 return value; 1155 } 1156 } 1157 } 1158 1159 return defValue; 1160 } 1161 1162 public static Context getBaseContext(Context context) { 1163 while (context instanceof ContextWrapper) { 1164 context = ((ContextWrapper) context).getBaseContext(); 1165 } 1166 return context; 1167 } 1168 1169 public IBinder getBinder() { 1170 if (mBinder == null) { 1171 // create a dummy binder. We only need it be not null. 1172 mBinder = new IBinder() { 1173 @Override 1174 public String getInterfaceDescriptor() throws RemoteException { 1175 return null; 1176 } 1177 1178 @Override 1179 public boolean pingBinder() { 1180 return false; 1181 } 1182 1183 @Override 1184 public boolean isBinderAlive() { 1185 return false; 1186 } 1187 1188 @Override 1189 public IInterface queryLocalInterface(String descriptor) { 1190 return null; 1191 } 1192 1193 @Override 1194 public void dump(FileDescriptor fd, String[] args) throws RemoteException { 1195 1196 } 1197 1198 @Override 1199 public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { 1200 1201 } 1202 1203 @Override 1204 public boolean transact(int code, Parcel data, Parcel reply, int flags) 1205 throws RemoteException { 1206 return false; 1207 } 1208 1209 @Override 1210 public void linkToDeath(DeathRecipient recipient, int flags) 1211 throws RemoteException { 1212 1213 } 1214 1215 @Override 1216 public boolean unlinkToDeath(DeathRecipient recipient, int flags) { 1217 return false; 1218 } 1219 1220 @Override 1221 public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1222 String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver) { 1223 } 1224 }; 1225 } 1226 return mBinder; 1227 } 1228 1229 //------------ NOT OVERRIDEN -------------------- 1230 1231 @Override 1232 public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) { 1233 // pass 1234 return false; 1235 } 1236 1237 @Override 1238 public int checkCallingOrSelfPermission(String arg0) { 1239 // pass 1240 return 0; 1241 } 1242 1243 @Override 1244 public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) { 1245 // pass 1246 return 0; 1247 } 1248 1249 @Override 1250 public int checkCallingPermission(String arg0) { 1251 // pass 1252 return 0; 1253 } 1254 1255 @Override 1256 public int checkCallingUriPermission(Uri arg0, int arg1) { 1257 // pass 1258 return 0; 1259 } 1260 1261 @Override 1262 public int checkPermission(String arg0, int arg1, int arg2) { 1263 // pass 1264 return 0; 1265 } 1266 1267 @Override 1268 public int checkSelfPermission(String arg0) { 1269 // pass 1270 return 0; 1271 } 1272 1273 @Override 1274 public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) { 1275 // pass 1276 return 0; 1277 } 1278 1279 @Override 1280 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) { 1281 // pass 1282 return 0; 1283 } 1284 1285 @Override 1286 public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) { 1287 // pass 1288 return 0; 1289 } 1290 1291 @Override 1292 public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3, 1293 int arg4, int arg5) { 1294 // pass 1295 return 0; 1296 } 1297 1298 @Override 1299 public void clearWallpaper() { 1300 // pass 1301 1302 } 1303 1304 @Override 1305 public Context createPackageContext(String arg0, int arg1) { 1306 // pass 1307 return null; 1308 } 1309 1310 @Override 1311 public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) { 1312 // pass 1313 return null; 1314 } 1315 1316 @Override 1317 public Context createConfigurationContext(Configuration overrideConfiguration) { 1318 // pass 1319 return null; 1320 } 1321 1322 @Override 1323 public Context createDisplayContext(Display display) { 1324 // pass 1325 return null; 1326 } 1327 1328 @Override 1329 public Context createContextForSplit(String splitName) { 1330 // pass 1331 return null; 1332 } 1333 1334 @Override 1335 public String[] databaseList() { 1336 // pass 1337 return null; 1338 } 1339 1340 @Override 1341 public Context createApplicationContext(ApplicationInfo application, int flags) 1342 throws PackageManager.NameNotFoundException { 1343 return null; 1344 } 1345 1346 @Override 1347 public boolean moveDatabaseFrom(Context sourceContext, String name) { 1348 // pass 1349 return false; 1350 } 1351 1352 @Override 1353 public boolean deleteDatabase(String arg0) { 1354 // pass 1355 return false; 1356 } 1357 1358 @Override 1359 public boolean deleteFile(String arg0) { 1360 // pass 1361 return false; 1362 } 1363 1364 @Override 1365 public void enforceCallingOrSelfPermission(String arg0, String arg1) { 1366 // pass 1367 1368 } 1369 1370 @Override 1371 public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1, 1372 String arg2) { 1373 // pass 1374 1375 } 1376 1377 @Override 1378 public void enforceCallingPermission(String arg0, String arg1) { 1379 // pass 1380 1381 } 1382 1383 @Override 1384 public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) { 1385 // pass 1386 1387 } 1388 1389 @Override 1390 public void enforcePermission(String arg0, int arg1, int arg2, String arg3) { 1391 // pass 1392 1393 } 1394 1395 @Override 1396 public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3, 1397 String arg4) { 1398 // pass 1399 1400 } 1401 1402 @Override 1403 public void enforceUriPermission(Uri arg0, String arg1, String arg2, 1404 int arg3, int arg4, int arg5, String arg6) { 1405 // pass 1406 1407 } 1408 1409 @Override 1410 public String[] fileList() { 1411 // pass 1412 return null; 1413 } 1414 1415 @Override 1416 public BridgeAssetManager getAssets() { 1417 return mAssets; 1418 } 1419 1420 @Override 1421 public File getCacheDir() { 1422 // pass 1423 return null; 1424 } 1425 1426 @Override 1427 public File getCodeCacheDir() { 1428 // pass 1429 return null; 1430 } 1431 1432 @Override 1433 public File getExternalCacheDir() { 1434 // pass 1435 return null; 1436 } 1437 1438 @Override 1439 public File getPreloadsFileCache() { 1440 // pass 1441 return null; 1442 } 1443 1444 @Override 1445 public ContentResolver getContentResolver() { 1446 if (mContentResolver == null) { 1447 mContentResolver = new BridgeContentResolver(this); 1448 } 1449 return mContentResolver; 1450 } 1451 1452 @Override 1453 public File getDatabasePath(String arg0) { 1454 // pass 1455 return null; 1456 } 1457 1458 @Override 1459 public File getDir(String arg0, int arg1) { 1460 // pass 1461 return null; 1462 } 1463 1464 @Override 1465 public File getFileStreamPath(String arg0) { 1466 // pass 1467 return null; 1468 } 1469 1470 @Override 1471 public File getSharedPreferencesPath(String name) { 1472 // pass 1473 return null; 1474 } 1475 1476 @Override 1477 public File getDataDir() { 1478 // pass 1479 return null; 1480 } 1481 1482 @Override 1483 public File getFilesDir() { 1484 // pass 1485 return null; 1486 } 1487 1488 @Override 1489 public File getNoBackupFilesDir() { 1490 // pass 1491 return null; 1492 } 1493 1494 @Override 1495 public File getExternalFilesDir(String type) { 1496 // pass 1497 return null; 1498 } 1499 1500 @Override 1501 public String getPackageCodePath() { 1502 // pass 1503 return null; 1504 } 1505 1506 @Override 1507 public String getBasePackageName() { 1508 // pass 1509 return null; 1510 } 1511 1512 @Override 1513 public String getOpPackageName() { 1514 // pass 1515 return null; 1516 } 1517 1518 @Override 1519 public ApplicationInfo getApplicationInfo() { 1520 return mApplicationInfo; 1521 } 1522 1523 @Override 1524 public String getPackageResourcePath() { 1525 // pass 1526 return null; 1527 } 1528 1529 @Override 1530 public SharedPreferences getSharedPreferences(String arg0, int arg1) { 1531 if (mSharedPreferences == null) { 1532 mSharedPreferences = new BridgeSharedPreferences(); 1533 } 1534 return mSharedPreferences; 1535 } 1536 1537 @Override 1538 public SharedPreferences getSharedPreferences(File arg0, int arg1) { 1539 if (mSharedPreferences == null) { 1540 mSharedPreferences = new BridgeSharedPreferences(); 1541 } 1542 return mSharedPreferences; 1543 } 1544 1545 @Override 1546 public boolean moveSharedPreferencesFrom(Context sourceContext, String name) { 1547 // pass 1548 return false; 1549 } 1550 1551 @Override 1552 public boolean deleteSharedPreferences(String name) { 1553 // pass 1554 return false; 1555 } 1556 1557 @Override 1558 public Drawable getWallpaper() { 1559 // pass 1560 return null; 1561 } 1562 1563 @Override 1564 public int getWallpaperDesiredMinimumWidth() { 1565 return -1; 1566 } 1567 1568 @Override 1569 public int getWallpaperDesiredMinimumHeight() { 1570 return -1; 1571 } 1572 1573 @Override 1574 public void grantUriPermission(String arg0, Uri arg1, int arg2) { 1575 // pass 1576 1577 } 1578 1579 @Override 1580 public FileInputStream openFileInput(String arg0) throws FileNotFoundException { 1581 // pass 1582 return null; 1583 } 1584 1585 @Override 1586 public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException { 1587 // pass 1588 return null; 1589 } 1590 1591 @Override 1592 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) { 1593 // pass 1594 return null; 1595 } 1596 1597 @Override 1598 public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, 1599 CursorFactory arg2, DatabaseErrorHandler arg3) { 1600 // pass 1601 return null; 1602 } 1603 1604 @Override 1605 public Drawable peekWallpaper() { 1606 // pass 1607 return null; 1608 } 1609 1610 @Override 1611 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) { 1612 // pass 1613 return null; 1614 } 1615 1616 @Override 1617 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, int arg2) { 1618 // pass 1619 return null; 1620 } 1621 1622 @Override 1623 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, 1624 String arg2, Handler arg3) { 1625 // pass 1626 return null; 1627 } 1628 1629 @Override 1630 public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, 1631 String arg2, Handler arg3, int arg4) { 1632 // pass 1633 return null; 1634 } 1635 1636 @Override 1637 public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5, 1638 IntentFilter arg1, String arg2, Handler arg3) { 1639 // pass 1640 return null; 1641 } 1642 1643 @Override 1644 public void removeStickyBroadcast(Intent arg0) { 1645 // pass 1646 1647 } 1648 1649 @Override 1650 public void revokeUriPermission(Uri arg0, int arg1) { 1651 // pass 1652 1653 } 1654 1655 @Override 1656 public void revokeUriPermission(String arg0, Uri arg1, int arg2) { 1657 // pass 1658 1659 } 1660 1661 @Override 1662 public void sendBroadcast(Intent arg0) { 1663 // pass 1664 1665 } 1666 1667 @Override 1668 public void sendBroadcast(Intent arg0, String arg1) { 1669 // pass 1670 1671 } 1672 1673 @Override 1674 public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { 1675 // pass 1676 1677 } 1678 1679 @Override 1680 public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) { 1681 // pass 1682 1683 } 1684 1685 @Override 1686 public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { 1687 // pass 1688 } 1689 1690 @Override 1691 public void sendOrderedBroadcast(Intent arg0, String arg1) { 1692 // pass 1693 1694 } 1695 1696 @Override 1697 public void sendOrderedBroadcast(Intent arg0, String arg1, 1698 BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, 1699 Bundle arg6) { 1700 // pass 1701 1702 } 1703 1704 @Override 1705 public void sendOrderedBroadcast(Intent arg0, String arg1, 1706 Bundle arg7, BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, 1707 Bundle arg6) { 1708 // pass 1709 1710 } 1711 1712 @Override 1713 public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, 1714 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, 1715 String initialData, Bundle initialExtras) { 1716 // pass 1717 } 1718 1719 @Override 1720 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 1721 // pass 1722 } 1723 1724 @Override 1725 public void sendBroadcastAsUser(Intent intent, UserHandle user, 1726 String receiverPermission) { 1727 // pass 1728 } 1729 1730 @Override 1731 public void sendBroadcastAsUser(Intent intent, UserHandle user, 1732 String receiverPermission, Bundle options) { 1733 // pass 1734 } 1735 1736 public void sendBroadcastAsUser(Intent intent, UserHandle user, 1737 String receiverPermission, int appOp) { 1738 // pass 1739 } 1740 1741 @Override 1742 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1743 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 1744 int initialCode, String initialData, Bundle initialExtras) { 1745 // pass 1746 } 1747 1748 @Override 1749 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1750 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 1751 Handler scheduler, 1752 int initialCode, String initialData, Bundle initialExtras) { 1753 // pass 1754 } 1755 1756 @Override 1757 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 1758 String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, 1759 Handler scheduler, 1760 int initialCode, String initialData, Bundle initialExtras) { 1761 // pass 1762 } 1763 1764 @Override 1765 public void sendStickyBroadcast(Intent arg0) { 1766 // pass 1767 1768 } 1769 1770 @Override 1771 public void sendStickyOrderedBroadcast(Intent intent, 1772 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, 1773 Bundle initialExtras) { 1774 // pass 1775 } 1776 1777 @Override 1778 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { 1779 // pass 1780 } 1781 1782 @Override 1783 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { 1784 // pass 1785 } 1786 1787 @Override 1788 public void sendStickyOrderedBroadcastAsUser(Intent intent, 1789 UserHandle user, BroadcastReceiver resultReceiver, 1790 Handler scheduler, int initialCode, String initialData, 1791 Bundle initialExtras) { 1792 // pass 1793 } 1794 1795 @Override 1796 public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { 1797 // pass 1798 } 1799 1800 @Override 1801 public void setTheme(int arg0) { 1802 // pass 1803 1804 } 1805 1806 @Override 1807 public void setWallpaper(Bitmap arg0) throws IOException { 1808 // pass 1809 1810 } 1811 1812 @Override 1813 public void setWallpaper(InputStream arg0) throws IOException { 1814 // pass 1815 1816 } 1817 1818 @Override 1819 public void startActivity(Intent arg0) { 1820 // pass 1821 } 1822 1823 @Override 1824 public void startActivity(Intent arg0, Bundle arg1) { 1825 // pass 1826 } 1827 1828 @Override 1829 public void startIntentSender(IntentSender intent, 1830 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) 1831 throws IntentSender.SendIntentException { 1832 // pass 1833 } 1834 1835 @Override 1836 public void startIntentSender(IntentSender intent, 1837 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, 1838 Bundle options) throws IntentSender.SendIntentException { 1839 // pass 1840 } 1841 1842 @Override 1843 public boolean startInstrumentation(ComponentName arg0, String arg1, 1844 Bundle arg2) { 1845 // pass 1846 return false; 1847 } 1848 1849 @Override 1850 public ComponentName startService(Intent arg0) { 1851 // pass 1852 return null; 1853 } 1854 1855 @Override 1856 public ComponentName startForegroundService(Intent service) { 1857 // pass 1858 return null; 1859 } 1860 1861 @Override 1862 public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) { 1863 // pass 1864 return null; 1865 } 1866 1867 @Override 1868 public boolean stopService(Intent arg0) { 1869 // pass 1870 return false; 1871 } 1872 1873 @Override 1874 public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) { 1875 // pass 1876 return null; 1877 } 1878 1879 @Override 1880 public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) { 1881 // pass 1882 return false; 1883 } 1884 1885 @Override 1886 public void unbindService(ServiceConnection arg0) { 1887 // pass 1888 1889 } 1890 1891 @Override 1892 public void unregisterReceiver(BroadcastReceiver arg0) { 1893 // pass 1894 1895 } 1896 1897 @Override 1898 public Context getApplicationContext() { 1899 return this; 1900 } 1901 1902 @Override 1903 public void startActivities(Intent[] arg0) { 1904 // pass 1905 1906 } 1907 1908 @Override 1909 public void startActivities(Intent[] arg0, Bundle arg1) { 1910 // pass 1911 1912 } 1913 1914 @Override 1915 public boolean isRestricted() { 1916 return false; 1917 } 1918 1919 @Override 1920 public File getObbDir() { 1921 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null); 1922 return null; 1923 } 1924 1925 @Override 1926 public DisplayAdjustments getDisplayAdjustments(int displayId) { 1927 // pass 1928 return null; 1929 } 1930 1931 @Override 1932 public Display getDisplay() { 1933 // pass 1934 return null; 1935 } 1936 1937 @Override 1938 public void updateDisplay(int displayId) { 1939 // pass 1940 } 1941 1942 @Override 1943 public int getUserId() { 1944 return 0; // not used 1945 } 1946 1947 @Override 1948 public File[] getExternalFilesDirs(String type) { 1949 // pass 1950 return new File[0]; 1951 } 1952 1953 @Override 1954 public File[] getObbDirs() { 1955 // pass 1956 return new File[0]; 1957 } 1958 1959 @Override 1960 public File[] getExternalCacheDirs() { 1961 // pass 1962 return new File[0]; 1963 } 1964 1965 @Override 1966 public File[] getExternalMediaDirs() { 1967 // pass 1968 return new File[0]; 1969 } 1970 1971 public void setScrollYPos(@NonNull View view, int scrollPos) { 1972 mScrollYPos.put(view, scrollPos); 1973 } 1974 1975 public int getScrollYPos(@NonNull View view) { 1976 Integer pos = mScrollYPos.get(view); 1977 return pos != null ? pos : 0; 1978 } 1979 1980 public void setScrollXPos(@NonNull View view, int scrollPos) { 1981 mScrollXPos.put(view, scrollPos); 1982 } 1983 1984 public int getScrollXPos(@NonNull View view) { 1985 Integer pos = mScrollXPos.get(view); 1986 return pos != null ? pos : 0; 1987 } 1988 1989 @Override 1990 public Context createDeviceProtectedStorageContext() { 1991 // pass 1992 return null; 1993 } 1994 1995 @Override 1996 public Context createCredentialProtectedStorageContext() { 1997 // pass 1998 return null; 1999 } 2000 2001 @Override 2002 public boolean isDeviceProtectedStorage() { 2003 return false; 2004 } 2005 2006 @Override 2007 public boolean isCredentialProtectedStorage() { 2008 return false; 2009 } 2010 2011 @Override 2012 public boolean canLoadUnsafeResources() { 2013 return false; 2014 } 2015 2016 /** 2017 * The cached value depends on 2018 * <ol> 2019 * <li>{@code int[]}: the attributes for which TypedArray is created </li> 2020 * <li>{@code List<StyleResourceValue>}: the themes set on the context at the time of 2021 * creation of the TypedArray</li> 2022 * <li>{@code Integer}: the default style used at the time of creation</li> 2023 * </ol> 2024 * 2025 * The class is created by using nested maps resolving one dependency at a time. 2026 * <p/> 2027 * The final value of the nested maps is a pair of the typed array and a map of properties 2028 * that should be added to {@link #mDefaultPropMaps}, if needed. 2029 */ 2030 private static class TypedArrayCache { 2031 2032 private Map<int[], 2033 Map<List<StyleResourceValue>, 2034 Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>> mCache; 2035 2036 private TypedArrayCache() { 2037 mCache = new IdentityHashMap<>(); 2038 } 2039 2040 public Pair<BridgeTypedArray, PropertiesMap> get(int[] attrs, 2041 List<StyleResourceValue> themes, int resId) { 2042 Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>> 2043 cacheFromThemes = mCache.get(attrs); 2044 if (cacheFromThemes != null) { 2045 Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId = 2046 cacheFromThemes.get(themes); 2047 if (cacheFromResId != null) { 2048 return cacheFromResId.get(resId); 2049 } 2050 } 2051 return null; 2052 } 2053 2054 public void put(int[] attrs, List<StyleResourceValue> themes, int resId, 2055 Pair<BridgeTypedArray, PropertiesMap> value) { 2056 Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>> 2057 cacheFromThemes = mCache.computeIfAbsent(attrs, k -> new HashMap<>()); 2058 Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId = 2059 cacheFromThemes.computeIfAbsent(themes, k -> new HashMap<>()); 2060 cacheFromResId.put(resId, value); 2061 } 2062 2063 } 2064} 2065