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