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