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