aboutsummaryrefslogtreecommitdiff
path: root/bridge/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'bridge/src/com')
-rw-r--r--bridge/src/com/android/layoutlib/bridge/Bridge.java2
-rw-r--r--bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java40
-rw-r--r--bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java5
-rw-r--r--bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java5
-rw-r--r--bridge/src/com/android/layoutlib/bridge/bars/Config.java7
-rw-r--r--bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java48
-rw-r--r--bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java59
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/Layout.java21
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java20
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java56
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java97
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java4
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java5
-rw-r--r--bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java8
14 files changed, 236 insertions, 141 deletions
diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 3c62193dad..ce0fb2ddd8 100644
--- a/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -337,7 +337,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
}
/**
- * Tests if the field is pubic, static and one of int or int[].
+ * Tests if the field is public, static and one of int or int[].
*/
private static boolean isValidRField(Field field) {
int modifiers = field.getModifiers();
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index a0cf2b23b2..9bffc23eb3 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -40,6 +40,7 @@ import com.android.tools.layoutlib.annotations.NotNull;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.animation.AnimationHandler;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -81,6 +82,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
+import android.os.NullVibrator;
+import android.os.NullVibratorManager;
import android.os.Parcel;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -170,7 +173,7 @@ public class BridgeContext extends Context {
private final LayoutlibCallback mLayoutlibCallback;
private final WindowManager mWindowManager;
private final DisplayManager mDisplayManager;
- private final AutofillManager mAutofillManager;
+ private AutofillManager mAutofillManager;
private final ClipboardManager mClipboardManager;
private final ActivityManager mActivityManager;
private final ConnectivityManager mConnectivityManager;
@@ -199,10 +202,12 @@ public class BridgeContext extends Context {
private Boolean mIsThemeAppCompat;
private boolean mUseThemedIcon;
private Context mApplicationContext;
+ private AccessibilityManager mAccessibilityManager;
private final ResourceNamespace mAppCompatNamespace;
private final Map<Key<?>, Object> mUserData = new HashMap<>();
private final SessionInteractiveData mSessionInteractiveData;
+ private final ThreadLocal<AnimationHandler> mAnimationHandlerThreadLocal = new ThreadLocal<>();
/**
* Some applications that target both pre API 17 and post API 17, set the newer attrs to
@@ -263,7 +268,6 @@ public class BridgeContext extends Context {
mWindowManager = new WindowManagerImpl(this, mMetrics);
mDisplayManager = new DisplayManager(this);
- mAutofillManager = new AutofillManager(this, new Default());
mClipboardManager = new ClipboardManager(this, null);
mActivityManager = ActivityManager_Accessor.getActivityManagerInstance(this);
mConnectivityManager = new ConnectivityManager(this, null);
@@ -462,9 +466,12 @@ public class BridgeContext extends Context {
try {
outValue.data = Integer.parseInt(stringValue);
outValue.type = TypedValue.TYPE_INT_DEC;
- } catch (NumberFormatException e) {
- outValue.type = TypedValue.TYPE_STRING;
- outValue.string = stringValue;
+ }
+ catch (NumberFormatException e) {
+ if (!ResourceHelper.parseFloatAttribute(null, stringValue, outValue, false)) {
+ outValue.type = TypedValue.TYPE_STRING;
+ outValue.string = stringValue;
+ }
}
}
}
@@ -601,6 +608,13 @@ public class BridgeContext extends Context {
return isThemeAppCompat;
}
+ public AccessibilityManager getAccessibilityManager() {
+ if (mAccessibilityManager == null) {
+ mAccessibilityManager = new AccessibilityManager(this, null, UserHandle.USER_CURRENT);
+ }
+ return mAccessibilityManager;
+ }
+
// ------------ Context methods
@Override
@@ -673,6 +687,9 @@ public class BridgeContext extends Context {
return InputMethodManager.forContext(this);
case AUTOFILL_MANAGER_SERVICE:
+ if (mAutofillManager == null) {
+ mAutofillManager = new AutofillManager(this, new Default());
+ }
return mAutofillManager;
case CLIPBOARD_SERVICE:
@@ -690,6 +707,12 @@ public class BridgeContext extends Context {
case INPUT_SERVICE:
return mInputManager;
+ case VIBRATOR_SERVICE:
+ return NullVibrator.getInstance();
+
+ case VIBRATOR_MANAGER_SERVICE:
+ return NullVibratorManager.getInstance();
+
case TEXT_CLASSIFICATION_SERVICE:
case CONTENT_CAPTURE_MANAGER_SERVICE:
case ALARM_SERVICE:
@@ -1525,7 +1548,7 @@ public class BridgeContext extends Context {
@Override
public ContentResolver getContentResolver() {
if (mContentResolver == null) {
- mContentResolver = new BridgeContentResolver(this);
+ mContentResolver = new BridgeContentResolver(getApplicationContext());
}
return mContentResolver;
}
@@ -2289,4 +2312,9 @@ public class BridgeContext extends Context {
public void applyWallpaper(String wallpaperPath) {
mRenderResources.setWallpaper(wallpaperPath, mConfig.isNightModeActive());
}
+
+ @NotNull
+ public ThreadLocal<AnimationHandler> getAnimationHandlerThreadLocal() {
+ return mAnimationHandlerThreadLocal;
+ }
}
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 85bf637d00..c376429186 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -61,6 +61,11 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
+ public boolean isBatterySaverSupported() throws RemoteException {
+ return true;
+ }
+
+ @Override
public BatterySaverPolicyConfig getFullPowerSavePolicy() {
return new BatterySaverPolicyConfig.Builder().build();
}
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java
index 5fe116ea0c..0122da1818 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java
@@ -90,4 +90,9 @@ public class BridgeThermalService implements IThermalService {
public float getThermalHeadroom(int forecastSeconds) {
return Float.NaN;
}
+
+ @Override
+ public float[] getThermalHeadroomThresholds() {
+ return new float[]{};
+ }
}
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index d89960ea68..794990852a 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -92,8 +92,8 @@ public class Config {
}
public static String getTime(int platformVersion) {
- if (isGreaterOrEqual(platformVersion, TIRAMISU)) {
- return "13:00";
+ if (isGreaterOrEqual(platformVersion, UPSIDE_DOWN_CAKE)) {
+ return "14:00";
}
if (platformVersion < GINGERBREAD) {
return "2:20";
@@ -143,6 +143,9 @@ public class Config {
if (platformVersion < TIRAMISU) {
return "12:00";
}
+ if (platformVersion < UPSIDE_DOWN_CAKE) {
+ return "13:00";
+ }
// Should never happen.
return "4:04";
}
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 63efec36f1..98378e63e1 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -24,18 +24,13 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ResourceHelper;
-import com.android.layoutlib.bridge.resources.IconLoader;
import com.android.layoutlib.bridge.resources.SysUiResources;
import com.android.resources.Density;
-import com.android.resources.LayoutDirection;
import com.android.resources.ResourceType;
import android.annotation.NonNull;
import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.Gravity;
@@ -45,12 +40,10 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import java.io.InputStream;
-
import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
/**
- * Base "bar" class for the window decor around the the edited layout.
+ * Base "bar" class for the window decor around the edited layout.
* This is basically an horizontal layout that loads a given layout on creation (it is read
* through {@link Class#getResourceAsStream(String)}).
* <p>
@@ -88,9 +81,9 @@ abstract class CustomBar extends LinearLayout {
layoutName);
}
- protected ImageView loadIcon(ImageView imageView, String iconName, Density density) {
+ protected ImageView loadIcon(ImageView imageView, String iconName, Density density, int color) {
return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName,
- density, false);
+ density, false, color);
}
protected ImageView loadIcon(int index, String iconName, Density density, boolean isRtl) {
@@ -98,39 +91,12 @@ abstract class CustomBar extends LinearLayout {
if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName,
- density, isRtl);
+ density, isRtl, Color.WHITE);
}
return null;
}
- protected ImageView loadIcon(ImageView imageView, String iconName, Density density,
- boolean isRtl) {
- LayoutDirection dir = isRtl ? LayoutDirection.RTL : null;
- IconLoader iconLoader = new IconLoader(iconName, density, mSimulatedPlatformVersion, dir);
- InputStream stream = iconLoader.getIcon();
-
- if (stream != null) {
- density = iconLoader.getDensity();
- String path = iconLoader.getPath();
- // look for a cached bitmap
- Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/);
- if (bitmap == null) {
- Options options = new Options();
- options.inDensity = density.getDpiValue();
- bitmap = BitmapFactory.decodeStream(stream, null, options);
- Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
- }
-
- if (bitmap != null) {
- BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
- imageView.setImageDrawable(drawable);
- }
- }
-
- return imageView;
- }
-
protected TextView setText(int index, String string) {
View child = getChildAt(index);
if (child instanceof TextView) {
@@ -247,9 +213,7 @@ abstract class CustomBar extends LinearLayout {
resource = renderResources.resolveResValue(resource);
if (resource != null) {
ResourceType type = resource.getResourceType();
- if (type == null || type == ResourceType.COLOR) {
- // if no type is specified, the value may have been specified directly in the style
- // file, rather than referencing a color resource value.
+ if (type == ResourceType.STYLE_ITEM || type == ResourceType.COLOR) {
try {
return ResourceHelper.getColor(resource.getValue());
} catch (NumberFormatException e) {
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index dc823f7e37..68423337a0 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -17,11 +17,13 @@
package com.android.layoutlib.bridge.bars;
import com.android.ide.common.rendering.api.ILayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceNamespace;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ParserFactory;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.layoutlib.bridge.resources.IconLoader;
import com.android.resources.Density;
@@ -42,9 +44,24 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import static android.graphics.Color.WHITE;
+import static android.os._Original_Build.VERSION_CODES.M;
+import static com.android.layoutlib.bridge.bars.Config.getTimeColor;
+import static com.android.layoutlib.bridge.bars.Config.isGreaterOrEqual;
+
public class StatusBar extends CustomBar {
private final int mSimulatedPlatformVersion;
+ /**
+ * Color corresponding to light_mode_icon_color_single_tone
+ * from frameworks/base/packages/SettingsLib/res/values/colors.xml
+ */
+ private static final int LIGHT_ICON_COLOR = 0xffffffff;
+ /**
+ * Color corresponding to dark_mode_icon_color_single_tone
+ * from frameworks/base/packages/SettingsLib/res/values/colors.xml
+ */
+ private static final int DARK_ICON_COLOR = 0x99000000;
/** Status bar background color attribute name. */
private static final String ATTR_COLOR = "statusBarColor";
/** Attribute for translucency property. */
@@ -57,7 +74,7 @@ public class StatusBar extends CustomBar {
@SuppressWarnings("UnusedParameters")
public StatusBar(Context context, AttributeSet attrs) {
this((BridgeContext) context,
- Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+ Density.create(((BridgeContext) context).getMetrics().densityDpi),
((BridgeContext) context).getConfiguration().getLayoutDirection() ==
View.LAYOUT_DIRECTION_RTL,
(context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
@@ -95,20 +112,45 @@ public class StatusBar extends CustomBar {
return;
}
+ int foregroundColor = getForegroundColor(simulatedPlatformVersion);
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
loadIcon(icons.get(0), "stat_sys_wifi_signal_4_fully."
- + Config.getWifiIconType(simulatedPlatformVersion), density);
- loadIcon(icons.get(1), "stat_sys_battery_100.png", density);
+ + Config.getWifiIconType(simulatedPlatformVersion), density,foregroundColor);
+ loadIcon(icons.get(1), "stat_sys_battery_100.png", density, foregroundColor);
clockView.setText(Config.getTime(simulatedPlatformVersion));
- clockView.setTextColor(Config.getTimeColor(simulatedPlatformVersion));
+ clockView.setTextColor(foregroundColor);
+ }
+
+ private int getForegroundColor(int platformVersion) {
+ if (isGreaterOrEqual(platformVersion, M)) {
+ RenderResources renderResources = getContext().getRenderResources();
+ boolean translucentBackground =
+ ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources,
+ ATTR_TRANSLUCENT, false);
+ if (translucentBackground) {
+ return WHITE;
+ }
+ boolean drawnByWindow =
+ ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources,
+ "windowDrawsSystemBarBackgrounds", false);
+ if (drawnByWindow) {
+ boolean lightStatusBar =
+ ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources,
+ "windowLightStatusBar", false);
+ return lightStatusBar ? DARK_ICON_COLOR : LIGHT_ICON_COLOR;
+ }
+ return WHITE;
+ } else {
+ return getTimeColor(platformVersion);
+ }
}
@Override
- protected ImageView loadIcon(ImageView imageView, String iconName, Density density) {
+ protected ImageView loadIcon(ImageView imageView, String iconName, Density density, int color) {
if (!iconName.endsWith(".xml")) {
- return super.loadIcon(imageView, iconName, density);
+ return super.loadIcon(imageView, iconName, density, color);
}
// The xml is stored only in xhdpi.
@@ -123,8 +165,9 @@ public class StatusBar extends CustomBar {
ParserFactory.create(stream, iconName),
(BridgeContext) mContext,
ResourceNamespace.ANDROID);
- imageView.setImageDrawable(
- Drawable.createFromXml(mContext.getResources(), parser));
+ Drawable drawable = Drawable.createFromXml(mContext.getResources(), parser);
+ drawable.setTint(color);
+ imageView.setImageDrawable(drawable);
} catch (XmlPullParserException e) {
Bridge.getLog().error(ILayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
null, null);
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
index c8e5009888..1ca3b9c2cc 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
@@ -38,6 +38,8 @@ import com.android.resources.ScreenOrientation;
import android.R.id;
import android.annotation.NonNull;
import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -196,6 +198,25 @@ class Layout extends FrameLayout {
mBuilder = null;
}
+ @Override
+ public boolean getChildVisibleRect(View child, Rect r, Point offset, boolean forceParentCheck) {
+ return r.intersect(0, 0, getWidth(), getHeight());
+ }
+
+ @Override
+ public boolean getGlobalVisibleRect(Rect r, Point globalOffset) {
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
+ if (width > 0 && height > 0) {
+ r.set(0, 0, width, height);
+ if (globalOffset != null) {
+ globalOffset.set(-mScrollX, -mScrollY);
+ }
+ return true;
+ }
+ return false;
+ }
+
@NonNull
private static View createSysUiOverlay(@NonNull BridgeContext context) {
SysUiOverlay overlay = new SysUiOverlay(context, 20, 10, 50, 40, 60);
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index c2430a8959..98b59565f7 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -32,6 +32,7 @@ import com.android.tools.layoutlib.annotations.NotNull;
import com.android.tools.layoutlib.annotations.Nullable;
import com.android.tools.layoutlib.annotations.VisibleForTesting;
+import android.animation.AnimationHandler;
import android.animation.PropertyValuesHolder_Accessor;
import android.content.res.Configuration;
import android.graphics.drawable.AdaptiveIconDrawable_Delegate;
@@ -42,6 +43,7 @@ import android.view.IWindowManagerImpl;
import android.view.Surface;
import android.view.ViewConfiguration_Accessor;
import android.view.WindowManagerGlobal_Delegate;
+import android.view.accessibility.AccessibilityInteractionClient_Accessor;
import android.view.inputmethod.InputMethodManager_Accessor;
import java.util.Collections;
@@ -51,6 +53,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
+import static android.os._Original_Build.VERSION.SDK_INT;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
@@ -68,6 +71,12 @@ import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
*
*/
public abstract class RenderAction<T extends RenderParams> {
+ /**
+ * Static field to store an SDK version coming from the render configuration.
+ * This is to be accessed when wanting to know the simulated SDK version instead
+ * of Build.VERSION.SDK_INT.
+ */
+ public static int sSimulatedSdk;
private static final Set<String> COMPOSE_CLASS_FQNS =
Set.of("androidx.compose.ui.tooling.ComposeViewAdapter",
@@ -99,6 +108,7 @@ public abstract class RenderAction<T extends RenderParams> {
*/
protected RenderAction(T params) {
mParams = params;
+ sSimulatedSdk = SDK_INT;
}
/**
@@ -276,6 +286,7 @@ public abstract class RenderAction<T extends RenderParams> {
ILayoutLog currentLog = mParams.getLog();
Bridge.setLog(currentLog);
mContext.getRenderResources().setLogger(currentLog);
+ AnimationHandler.sAnimatorHandler = mContext.getAnimationHandlerThreadLocal();
}
/**
@@ -303,6 +314,7 @@ public abstract class RenderAction<T extends RenderParams> {
ParserFactory.setParserFactory(null);
PropertyValuesHolder_Accessor.clearClassCaches();
+ AccessibilityInteractionClient_Accessor.clearCaches();
}
public static BridgeContext getCurrentContext() {
@@ -467,6 +479,14 @@ public abstract class RenderAction<T extends RenderParams> {
if (sCurrentContext != null) {
// quit HandlerThread created during this session.
HandlerThread_Delegate.cleanUp(sCurrentContext);
+
+ AnimationHandler animationHandler =
+ sCurrentContext.getAnimationHandlerThreadLocal().get();
+ if (animationHandler != null) {
+ animationHandler.mDelayedCallbackStartTime.clear();
+ animationHandler.mAnimationCallbacks.clear();
+ animationHandler.mCommitCallbacks.clear();
+ }
}
sCurrentContext = null;
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 6a6e184617..0dd35ce055 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -39,6 +39,7 @@ import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -78,7 +79,7 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
return Status.ERROR_NOT_A_DRAWABLE.createResult();
}
- Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context, context.getTheme());
if (d == null) {
return Status.ERROR_NOT_A_DRAWABLE.createResult();
}
@@ -128,15 +129,6 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
// Use screen size when either intrinsic width or height isn't available.
w = screenWidth;
h = screenHeight;
- } else if (w > screenWidth || h > screenHeight) {
- // If image wouldn't fit to the screen, resize it to avoid cropping.
-
- // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight.
- double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
-
- // scale * w / scale * h = w / h, so, proportions are preserved.
- w = (int) Math.floor(scale * w);
- h = (int) Math.floor(scale * h);
}
int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
@@ -149,46 +141,30 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
// Pre-draw setup.
AttachInfo_Accessor.dispatchOnPreDraw(content);
- // Draw into a new image.
- BufferedImage image = getImage(w, h);
-
- // Create an Android bitmap around the BufferedImage.
- Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),
- Config.ARGB_8888);
- bitmap.setPixels(image.getRGB(0, 0, image.getWidth(), image.getHeight(),
- null, 0, image.getWidth()), 0, image.getWidth(), 0, 0, image
- .getWidth(), image.getHeight());
-
- // Create a Canvas around the Android bitmap.
+ Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.setDensity(hardwareConfig.getDensity().getDpiValue());
// Draw.
content.draw(canvas);
- int[] pixels = new int[image.getWidth() * image.getHeight()];
- bitmap.getPixels(pixels, 0, image.getWidth(), 0, 0, image.getWidth(),
- image.getHeight());
- image.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
- // Detach root from window after draw.
- AttachInfo_Accessor.detachFromWindow(content);
+ if (w > screenWidth || h > screenHeight) {
+ // If image wouldn't fit to the screen, resize it to avoid cropping.
- return image;
- }
+ // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight.
+ double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
+ bitmap = Bitmap.createScaledBitmap(bitmap, (int) (w * scale), (int) (h * scale), true);
+ }
- @NonNull
- protected BufferedImage getImage(int w, int h) {
- BufferedImage image = new BufferedImage(w > 0 ? w : 1,
- h > 0 ? h : 1,
+ // Copy bitmap into BufferedImage.
+ BufferedImage image = new BufferedImage(bitmap.getWidth(), bitmap.getHeight(),
BufferedImage.TYPE_INT_ARGB);
- Graphics2D gc = image.createGraphics();
- gc.setComposite(AlphaComposite.Src);
-
- gc.setColor(new Color(0x00000000, true));
- gc.fillRect(0, 0, w, h);
+ int[] imageData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ bitmap.getPixels(imageData, 0, image.getWidth(), 0, 0, image.getWidth(),
+ image.getHeight());
- // done
- gc.dispose();
+ // Detach root from window after draw.
+ AttachInfo_Accessor.detachFromWindow(content);
return image;
}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index ae5e401edc..9ed5d17531 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -50,7 +50,6 @@ import com.android.tools.idea.validator.ValidatorHierarchy;
import com.android.tools.idea.validator.hierarchy.CustomHierarchyHelper;
import com.android.tools.layoutlib.annotations.NotNull;
-import android.animation.AnimationHandler;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -92,7 +91,10 @@ import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import static android.os._Original_Build.VERSION.SDK_INT;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
@@ -109,6 +111,10 @@ import static com.android.layoutlib.common.util.ReflectionUtils.isInstanceOf;
public class RenderSessionImpl extends RenderAction<SessionParams> {
private static final Canvas NOP_CANVAS = new NopCanvas();
+ private static final String SIMULATED_SDK_TOO_HIGH =
+ String.format("The current rendering only supports APIs up to %d. You may encounter " +
+ "crashes if using with higher APIs. To avoid, you can set a lower API for " +
+ "your previews.", SDK_INT);
// scene state
private RenderSession mScene;
@@ -198,7 +204,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
/**
- * Measures the the current layout if needed (see {@link #invalidateRenderingSize}).
+ * Measures the current layout if needed (see {@link #invalidateRenderingSize}).
*/
private void measureLayout(@NonNull SessionParams params) {
// only do the screen measure when needed.
@@ -310,6 +316,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
SessionParams params = getParams();
BridgeContext context = getContext();
+ int simulatedVersion = params.getSimulatedPlatformVersion();
+ sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT;
+ if (sSimulatedSdk > SDK_INT) {
+ Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED, SIMULATED_SDK_TOO_HIGH,
+ null, null, null);
+ }
+
if (Bridge.isLocaleRtl(params.getLocale())) {
if (!params.isRtlSupported()) {
Bridge.getLog().warning(ILayoutLog.TAG_RTL_NOT_ENABLED,
@@ -362,14 +375,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
mViewRoot.getViewRootImpl().mTmpFrames.displayFrame.set(mViewRoot.getLeft(),
mViewRoot.getTop(), mViewRoot.getRight(), mViewRoot.getBottom());
- ViewRootImpl rootImpl = AttachInfo_Accessor.getRootView(mViewRoot);
- if (rootImpl != null) {
- ViewRootImpl_Accessor.setChild(rootImpl, mViewRoot);
- }
-
mSystemViewInfoList =
- visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
- false);
+ visitAllChildren(mViewRoot, 0, 0, params, false);
return SUCCESS.createResult();
} catch (PostInflateException e) {
@@ -480,6 +487,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
SessionParams params = getParams();
+ int simulatedVersion = params.getSimulatedPlatformVersion();
+ sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT;
+ if (sSimulatedSdk > SDK_INT) {
+ Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED, SIMULATED_SDK_TOO_HIGH,
+ null, null, null);
+ }
+
try {
if (mViewRoot == null) {
return ERROR_NOT_INFLATED.createResult();
@@ -570,8 +584,12 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
mSystemViewInfoList =
- visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
- false);
+ visitAllChildren(mViewRoot, 0, 0, params, false);
+
+ Consumer<BufferedImage> imageTransformation = getParams().getImageTransformation();
+ if (imageTransformation != null) {
+ imageTransformation.accept(mImage);
+ }
boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR));
boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals(
@@ -853,15 +871,16 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
*
* @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
*/
- private ViewInfo visit(View view, int hOffset, int vOffset, boolean setExtendedInfo,
+ private ViewInfo visit(View view, int hOffset, int vOffset, SessionParams params,
boolean isContentFrame) {
- ViewInfo result = createViewInfo(view, hOffset, vOffset, setExtendedInfo, isContentFrame);
+ ViewInfo result = createViewInfo(view, hOffset, vOffset, params.getExtendedViewInfoMode(),
+ isContentFrame);
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
result.setChildren(visitAllChildren(group, isContentFrame ? 0 : hOffset,
isContentFrame ? 0 : vOffset,
- setExtendedInfo, isContentFrame));
+ params, isContentFrame));
}
return result;
}
@@ -880,7 +899,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* part of the system decor.
*/
private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int hOffset, int vOffset,
- boolean setExtendedInfo, boolean isContentFrame) {
+ SessionParams params, boolean isContentFrame) {
if (viewGroup == null) {
return null;
}
@@ -896,8 +915,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
List<ViewInfo> childrenWithOffset = new ArrayList<>(childCount);
for (int i = 0; i < childCount; i++) {
ViewInfo[] childViewInfo =
- visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset,
- setExtendedInfo);
+ visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset, params);
childrenWithoutOffset.add(childViewInfo[0]);
childrenWithOffset.add(childViewInfo[1]);
}
@@ -906,7 +924,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
} else {
List<ViewInfo> children = new ArrayList<>(childCount);
for (int i = 0; i < childCount; i++) {
- children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, setExtendedInfo,
+ children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, params,
isContentFrame));
}
return children;
@@ -920,26 +938,32 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* get the right bounds if the {@code ViewInfo} hierarchy is accessed from
* {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
* offset is not needed.
+ * If a custom parser was passed inside the {@link SessionParams} argument, this will be used
+ * to generate the {@link ViewInfo}s. Otherwise, {@link RenderSessionImpl#visitAllChildren}
+ * will be used.
*
* @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
* index 1 is with the offset.
*/
@NonNull
- private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset,
- boolean setExtendedInfo) {
+ private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset, SessionParams params) {
ViewInfo[] result = new ViewInfo[2];
if (view == null) {
return result;
}
+ boolean setExtendedInfo = params.getExtendedViewInfoMode();
result[0] = createViewInfo(view, 0, 0, setExtendedInfo, true);
result[1] = createViewInfo(view, hOffset, vOffset, setExtendedInfo, true);
- if (view instanceof ViewGroup) {
- List<ViewInfo> children =
- visitAllChildren((ViewGroup) view, 0, 0, setExtendedInfo, true);
- result[0].setChildren(children);
- result[1].setChildren(children);
+ Function<Object, List<ViewInfo>> customParser = params.getCustomContentHierarchyParser();
+ List<ViewInfo> children = null;
+ if (customParser != null) {
+ children = customParser.apply(view);
+ } else if (view instanceof ViewGroup) {
+ children = visitAllChildren((ViewGroup) view, 0, 0, params, true);
}
+ result[0].setChildren(children);
+ result[1].setChildren(children);
return result;
}
@@ -975,13 +999,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
shiftY + view.getTop(),
shiftX + view.getRight(),
shiftY + view.getBottom(),
- view, view.getLayoutParams());
+ view, null, view.getLayoutParams());
} else {
// We are part of the system decor.
SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
getViewKey(view),
view.getLeft(), view.getTop(), view.getRight(),
- view.getBottom(), view, view.getLayoutParams());
+ view.getBottom(), view, null, view.getLayoutParams());
result = r;
// We currently mark three kinds of views:
// 1. Menus in the Action Bar
@@ -1184,6 +1208,19 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
+ @Override
+ public void release() {
+ super.release();
+ if (mViewRoot == null) {
+ return;
+ }
+ ViewRootImpl viewRootImpl = mViewRoot.getViewRootImpl();
+ if (viewRootImpl == null) {
+ return;
+ }
+ ViewRootImpl_Accessor.detachFromWindow(viewRootImpl);
+ }
+
private void disposeImageSurface() {
if (mCanvas != null) {
mCanvas.release();
@@ -1198,12 +1235,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
mImage = null;
// detachFromWindow might create Handler callbacks, thus before Handler_Delegate.dispose
AttachInfo_Accessor.detachFromWindow(mViewRoot);
- AnimationHandler animationHandler = AnimationHandler.sAnimatorHandler.get();
- if (animationHandler != null) {
- animationHandler.mDelayedCallbackStartTime.clear();
- animationHandler.mAnimationCallbacks.clear();
- animationHandler.mCommitCallbacks.clear();
- }
getContext().getSessionInteractiveData().dispose();
if (mViewInfoList != null) {
mViewInfoList.clear();
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 87bed3d967..358795f256 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -111,7 +111,7 @@ import static android.content.res.AssetManager.ACCESS_STREAMING;
public final class ResourceHelper {
private static final Key<Set<ResourceValue>> KEY_GET_DRAWABLE =
Key.create("ResourceHelper.getDrawable");
- private static final Pattern sFloatPattern = Pattern.compile("(-?[0-9]*(?:\\.[0-9]+)?)(.*)");
+ private static final Pattern sFloatPattern = Pattern.compile("(-?[0-9]*(?:\\.[0-9]*)?)(.*)");
private static final float[] sFloatOut = new float[1];
private static final TypedValue mValue = new TypedValue();
@@ -368,7 +368,7 @@ public final class ResourceHelper {
if (value instanceof DensityBasedResourceValue) {
density = ((DensityBasedResourceValue) value).getResourceDensity();
if (density == Density.NODPI || density == Density.ANYDPI) {
- density = Density.getEnum(context.getConfiguration().densityDpi);
+ density = Density.create(context.getConfiguration().densityDpi);
}
}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java b/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java
index 9fea1677d5..6f9092cc12 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java
@@ -32,8 +32,9 @@ public class SystemViewInfo extends ViewInfo {
}
public SystemViewInfo(String name, Object cookie, int left, int top,
- int right, int bottom, Object viewObject, Object layoutParamsObject) {
- super(name, cookie, left, top, right, bottom, viewObject,
+ int right, int bottom, Object viewObject, Object accessibilityObject,
+ Object layoutParamsObject) {
+ super(name, cookie, left, top, right, bottom, viewObject, accessibilityObject,
layoutParamsObject);
}
diff --git a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
index 84ed6a04c4..f8884d4b2e 100644
--- a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
+++ b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
@@ -36,7 +36,6 @@ import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.BitmapDrawable;
import android.widget.ImageView;
-import java.io.IOException;
import java.io.InputStream;
public class SysUiResources {
@@ -67,10 +66,8 @@ public class SysUiResources {
return null;
}
- public static ImageView loadIcon(Context context, int api, ImageView imageView, String
- iconName,
- Density density, boolean
- isRtl) {
+ public static ImageView loadIcon(Context context, int api, ImageView imageView,
+ String iconName, Density density, boolean isRtl, int color) {
LayoutDirection dir = isRtl ? LayoutDirection.RTL : null;
IconLoader iconLoader = new IconLoader(iconName, density, api,
dir);
@@ -90,6 +87,7 @@ public class SysUiResources {
if (bitmap != null) {
BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bitmap);
+ drawable.setTint(color);
imageView.setImageDrawable(drawable);
}
}