Merge "bootanimation: fix garbage line issue when screen height is odd." into lmp-mr1-modular-dev
diff --git a/docs/html/training/swipe/add-swipe-interface.jd b/docs/html/training/swipe/add-swipe-interface.jd
new file mode 100644
index 0000000..ac15caf
--- /dev/null
+++ b/docs/html/training/swipe/add-swipe-interface.jd
@@ -0,0 +1,135 @@
+page.title=Adding Swipe-to-Refresh To Your App
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#AddSwipeWidget">Add the SwipeRefreshLayout Widget</a>
+ <li><a href="#AddRefreshAction">Add a Refresh Action to the Action Bar</a>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href=
+ "{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
+ </li>
+
+ <li>
+ <a href="{@docRoot}training/basics/actionbar/index.html">Adding the Action
+ Bar</a>
+ </li>
+</ul>
+
+<h2>Sample Apps</h2>
+
+<ul>
+ <li><a href="{@docRoot}samples/SwipeRefreshLayoutBasic/index.html">
+ SwipeRefreshLayoutBasic</a></li>
+ <li><a href="{@docRoot}samples/SwipeRefreshListFragment/index.html">
+ SwipeRefreshListFragment</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>
+ The swipe-to-refresh user interface pattern is implemented entirely within
+ the {@link android.support.v4.widget.SwipeRefreshLayout} widget, which
+ detects the vertical swipe, displays a distinctive progress bar, and triggers
+ callback methods in your app. You enable this behavior
+ by adding the widget to your layout file as the parent of a {@link
+ android.widget.ListView} or {@link android.widget.GridView}, and implementing
+ the refresh behavior that gets invoked when the user swipes.
+</p>
+
+<p>
+ This lesson shows you how to add the widget to an existing layout. It also
+ shows you how to add a refresh action to the action bar overflow area, so
+ that users who may be unable to use the swipe gesture can trigger a manual
+ update with an external device.
+</p>
+
+<h2 id="AddSwipeWidget">Add the SwipeRefreshLayout Widget</h2>
+<p>
+ To add the swipe to refresh widget to an existing app, add {@link
+ android.support.v4.widget.SwipeRefreshLayout} as the parent
+ of a single {@link android.widget.ListView} or {@link
+ android.widget.GridView}. Remember that {@link
+ android.support.v4.widget.SwipeRefreshLayout} only supports a single {@link
+ android.widget.ListView} or {@link android.widget.GridView} child.
+</p>
+
+<p>
+ The following example demonstrates how to add the {@link
+ android.support.v4.widget.SwipeRefreshLayout} widget to an existing layout
+ file containing a {@link android.widget.ListView}:
+</p>
+
+<pre><android.support.v4.widget.SwipeRefreshLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/swiperefresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</android.support.v4.widget.SwipeRefreshLayout></pre>
+
+<p>
+ You can also use the {@link android.support.v4.widget.SwipeRefreshLayout}
+ widget with a {@link android.support.v4.app.ListFragment}. If the layout
+ contains a {@link android.widget.ListView} with the ID
+ <code>"@android:id/list"</code>, the swipe-to-refresh functionality is
+ automatically supported. However, explicitly declaring the {@link
+ android.widget.ListView} in this way supersedes the default {@link
+ android.support.v4.app.ListFragment} view structure. If you want to use the
+ default view structure, you will have to override parts of the {@link
+ android.support.v4.widget.SwipeRefreshLayout} and {@link
+ android.support.v4.app.ListFragment} behavior. For an example of how to do
+ this, see the <a href=
+ "{@docRoot}samples/SwipeRefreshListFragment/index.html">SwipeRefreshListFragment</a>
+ sample app.
+</p>
+
+<h2 id="AddRefreshAction">Add a Refresh Action to the Action Bar</h2>
+
+<p>
+ You should add a refresh action to your app's action bar to ensure that
+ users who may not be able to perform a swipe gesture can still trigger a
+ manual update. For example, users with accessibility issues can trigger
+ action bar actions using external devices, such as keyboards and D-pads.
+</p>
+
+<p>
+ You should add the refresh action as a menu item,
+ rather than as a button, by setting the attribute
+ <code>android:showAsAction=never</code>. If you display the action as a
+ button, users may assume that the refresh button action is different from the
+ swipe-to-refresh action. By making the refresh action less conspicuous in the
+ action bar, you can encourage users to perform manual updates with the swipe
+ gesture while still maintaining the accessible option in a place where D-pad
+ users would look for it.
+</p>
+
+<p>
+ The following code demonstrates how to add the swipe-to-refresh action to the
+ overflow area:
+</p>
+
+<pre><menu xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item
+ android:id="@+id/menu_refresh"
+ android:showAsAction="never"
+ android:title="@string/menu_refresh"/>
+</menu></pre>
diff --git a/docs/html/training/swipe/images/swipe.mp4 b/docs/html/training/swipe/images/swipe.mp4
new file mode 100644
index 0000000..cd5c511
--- /dev/null
+++ b/docs/html/training/swipe/images/swipe.mp4
Binary files differ
diff --git a/docs/html/training/swipe/images/swipe_original.mp4 b/docs/html/training/swipe/images/swipe_original.mp4
new file mode 100644
index 0000000..abdf08f
--- /dev/null
+++ b/docs/html/training/swipe/images/swipe_original.mp4
Binary files differ
diff --git a/docs/html/training/swipe/index.jd b/docs/html/training/swipe/index.jd
new file mode 100644
index 0000000..17b4cf7
--- /dev/null
+++ b/docs/html/training/swipe/index.jd
@@ -0,0 +1,91 @@
+page.title=Supporting Swipe-to-Refresh
+trainingnavtop=true
+startpage=true
+
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 1.6 (API level 4) or later
+ </li>
+
+ <li>Latest version of the Android v4 <a href=
+ "{@docRoot}tools/support-library/index.html">Support Library</a>
+ </li>
+</ul>
+
+<h2>Sample Apps</h2>
+
+<ul>
+ <li><a href="{@docRoot}samples/SwipeRefreshLayoutBasic/index.html">
+ SwipeRefreshLayoutBasic</a></li>
+ <li><a href="{@docRoot}samples/SwipeRefreshListFragment/index.html">
+ SwipeRefreshListFragment</a></li>
+ <li><a href="{@docRoot}samples/SwipeRefreshMultipleViews/index.html">
+ SwipeRefreshMultipleViews</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>
+ Even if your app automatically updates its content on a regular basis, you
+ can allow users to request manual updates as well. For example, a weather
+ forecasting app can allow users get the latest forecasts on demand. To
+ provide a standard user experience for requesting updates, the Android
+ platform includes the swipe-to-refresh design pattern, which allows users
+ to trigger an update with a vertical swipe.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> This class requires the latest version of the Android
+ v4 Support Library APIs. If you have not used the Support Library before,
+ follow the instructions in the <a href=
+ "{@docRoot}tools/support-library/setup.html">Support Library Setup</a>
+ document.
+</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <b><a href="add-swipe-interface.html">Adding Swipe-to-Refresh To Your
+ App</a></b>
+ </dt>
+
+ <dd>
+ <div style="width:290px;margin-right:35px;float:right">
+ <div class="framed-nexus5-port-span-5">
+ <video class="play-on-hover" autoplay alt=
+ "When the user performs a swipe gesture, the SwipeRefreshLayout widget displays a progress indicator until your app finishes updating its data.">
+ <!-- Preferred video size 216x384 (portrait) -->
+ <source src="images/swipe.mp4">
+ </video>
+ </div>
+
+ <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+ <em>To replay the movie, click on the device screen</em>
+ </div>
+ </div>
+ </dd>
+
+ <dd>
+ Learn how to provide swipe-to-refresh support in a {@link
+ android.widget.ListView} or {@link android.widget.GridView}, and how to
+ provide an accessible refresh option using the action bar.
+ </dd>
+
+ <dt>
+ <b><a href="respond-refresh-request.html">Responding to a Refresh
+ Request</a></b>
+ </dt>
+
+ <dd>
+ Learn how to respond to the swipe-to-refresh gesture, and how to perform the
+ same update from an action bar action.
+ </dd>
+</dl>
diff --git a/docs/html/training/swipe/respond-refresh-request.jd b/docs/html/training/swipe/respond-refresh-request.jd
new file mode 100644
index 0000000..243b4a3
--- /dev/null
+++ b/docs/html/training/swipe/respond-refresh-request.jd
@@ -0,0 +1,158 @@
+page.title=Responding to a Refresh Request
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#RespondRefresh">Respond to the Refresh Gesture</a></li>
+ <li><a href="#RespondAction">Respond to the Refresh Action</a>
+</ol>
+
+<h2>Sample App</h2>
+
+<ul>
+ <li><a href="{@docRoot}samples/SwipeRefreshLayoutBasic/index.html">
+ SwipeRefreshLayoutBasic</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>
+ This lesson shows you how to update your app when the user requests a manual
+ refresh, whether the user triggers the refresh with a swipe gesture or by
+ using the action bar refresh action.
+</p>
+
+<h2 id="RespondRefresh">Respond to the Refresh Gesture</h2>
+
+<p>
+ When the user makes a swipe gesture, the system displays the progress
+ indicator and calls your app's callback method. Your callback method is
+ responsible for actually updating the app's data.
+</p>
+
+<p>
+ To respond to the refresh gesture in your app, implement the {@link
+ android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener} interface and
+ its {@link
+ android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener#onRefresh
+ onRefresh()} method. The {@link
+ android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener#onRefresh
+ onRefresh()} method is invoked when the user performs a swipe gesture.
+</p>
+
+<p>
+ You should put the code for the actual update
+ operation in a separate method, and call that update method from your {@link
+ android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener#onRefresh
+ onRefresh()} implementation. That way, you can use the same update method to
+ perform the update when the user triggers a refresh from the action bar.
+</p>
+
+<p>
+ Your update method calls {@link
+ android.support.v4.widget.SwipeRefreshLayout#setRefreshing
+ setRefreshing(false)} when it has finished updating the data. Calling this
+ method instructs the {@link android.support.v4.widget.SwipeRefreshLayout} to
+ remove the progress indicator and update the view contents.
+</p>
+
+<p>
+ For example, the following code implements {@link
+ android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener#onRefresh
+ onRefresh()} and invokes the method {@code myUpdateOperation()} to update the
+ data displayed by the {@link android.widget.ListView}:
+</p>
+
+<pre>/*
+ * Sets up a SwipeRefreshLayout.OnRefreshListener that is invoked when the user
+ * performs a swipe-to-refresh gesture.
+ */
+mySwipeRefreshLayout.setOnRefreshListener(
+ new SwipeRefreshLayout.OnRefreshListener() {
+ @Override
+ public void onRefresh() {
+ Log.i(LOG_TAG, "onRefresh called from SwipeRefreshLayout");
+
+ // This method performs the actual data-refresh operation.
+ // The method calls setRefreshing(false) when it's finished.
+ myUpdateOperation();
+ }
+ }
+);</pre>
+
+<h2 id="RespondAction">Respond to the Refresh Action</h2>
+
+<p>
+ If the user requests a refresh by using the action bar, the system calls the
+ {@link android.support.v4.app.Fragment#onOptionsItemSelected
+ onOptionsItemSelected()} method. Your app should respond to this call by
+ displaying the progress indicator and refreshing the app's data.
+</p>
+
+<p>
+ To respond to the refresh action, override {@link
+ android.support.v4.app.Fragment#onOptionsItemSelected
+ onOptionsItemSelected()}. In your override method, trigger the {@link
+ android.support.v4.widget.SwipeRefreshLayout} progress indicator by calling
+ {@link android.support.v4.widget.SwipeRefreshLayout#setRefreshing
+ setRefreshing()} with the value {@code true}, then perform the update
+ operation. Once again, you should be doing the actual update in a separate
+ method, so the same method can be called whether the user triggers the update
+ with a swipe or by using the action bar. When the update has finished, call
+ {@link android.support.v4.widget.SwipeRefreshLayout#setRefreshing
+ setRefreshing(false)} to remove the refresh progress indicator.
+</p>
+
+<p>The following code shows how to respond to the request action:
+</p>
+
+<pre>/*
+ * Listen for option item selections so that we receive a notification
+ * when the user requests a refresh by selecting the refresh action bar item.
+ */
+@Override
+public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ // Check if user triggered a refresh:
+ case R.id.menu_refresh:
+ Log.i(LOG_TAG, "Refresh menu item selected");
+
+ // Signal SwipeRefreshLayout to start the progress indicator
+ mySwipeRefreshLayout.setRefreshing(true);
+
+ // Start the refresh background task.
+ // This method calls setRefreshing(false) when it's finished.
+ myUpdateOperation();
+
+ return true;
+ }
+
+ // User didn't trigger a refresh, let the superclass handle this action
+ return super.onOptionsItemSelected(item);
+
+}</pre>
+
+<p class="note">
+ <strong>Note:</strong> When the user triggers a refresh with a swipe action as
+ described in <a href="#RespondRefresh">Respond to the Refresh Gesture</a>,
+ you do not need to call {@link
+ android.support.v4.widget.SwipeRefreshLayout#setRefreshing setRefreshing()}.
+ The {@link
+ android.support.v4.widget.SwipeRefreshLayout} widget takes care of displaying
+ the progress indicator and removing it when the update has finished. However,
+ if the update is triggered by any means <em>other than</em> a swipe gesture,
+ you need to explicitly turn the progress indicator on with {@link
+ android.support.v4.widget.SwipeRefreshLayout#setRefreshing setRefreshing()}.
+ The method which actually refreshes the data calls {@link
+ android.support.v4.widget.SwipeRefreshLayout#setRefreshing
+ setRefreshing(false)} to signal that the update is finished.
+</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 3ee7ab7..862663e 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1195,7 +1195,24 @@
</li>
</ul>
</li>
-
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/swipe/index.html"
+ description=
+ "How to modify your app's layout to support manual content updates triggered by the
+ swipe-to-refresh gesture."
+ >Supporting Swipe-to-Refresh</a>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/swipe/add-swipe-interface.html"
+ >Adding Swipe-to-Refresh To Your App</a></li>
+ <li>
+ <a href="<?cs var:toroot ?>training/swipe/respond-refresh-request.html"
+ >Responding to a Refresh Gesture</a>
+ </li>
+ </ul>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/search/index.html"
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 610c867..e9b5d6e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -23,6 +23,8 @@
import android.graphics.Shader.TileMode;
+import java.awt.image.ColorModel;
+
/**
* Delegate implementing the native methods of android.graphics.BitmapShader
*
@@ -124,6 +126,11 @@
localMatrix = new java.awt.geom.AffineTransform();
}
+ if (!colorModel.isCompatibleRaster(mImage.getRaster())) {
+ // Fallback to the default ARGB color model
+ colorModel = ColorModel.getRGBdefault();
+ }
+
return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
}
@@ -153,8 +160,9 @@
@Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(
+ mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
+ mColorModel.isAlphaPremultiplied(), null);
int[] data = new int[w*h];
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index 55c4b98..703719c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -172,8 +172,9 @@
@Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(
+ mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
+ mColorModel.isAlphaPremultiplied(), null);
int[] data = new int[w*h];
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 80179ee..6edb140 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -160,8 +160,9 @@
@Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(
+ mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
+ mColorModel.isAlphaPremultiplied(), null);
int[] data = new int[w*h];
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 95a57a9..544ba98 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -152,8 +152,9 @@
@Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(
+ mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
+ mColorModel.isAlphaPremultiplied(), null);
int[] data = new int[w*h];
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 5db9556..2e649c3 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -16,19 +16,15 @@
package android.view;
-import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.ide.common.rendering.api.MergeCookie;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
-import com.android.layoutlib.bridge.android.support.RecyclerViewUtil.LayoutManagerType;
import com.android.layoutlib.bridge.impl.ParserFactory;
-import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -233,22 +229,6 @@
if (viewKey != null) {
bc.addViewKey(view, viewKey);
}
- if (RenderSessionImpl.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
- String type = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES,
- BridgeConstants.ATTR_LAYOUT_MANAGER_TYPE);
- if (type != null) {
- LayoutManagerType layoutManagerType = LayoutManagerType.getByLogicalName(type);
- if (layoutManagerType == null) {
- layoutManagerType = LayoutManagerType.getByClassName(type);
- }
- if (layoutManagerType == null) {
- // add the classname itself.
- bc.addCookie(view, type);
- } else {
- bc.addCookie(view, layoutManagerType);
- }
- }
- }
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
index ec3a8d6..30512aa 100644
--- a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
@@ -19,6 +19,7 @@
import com.android.layoutlib.bridge.impl.ResourceHelper;
import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
import android.graphics.LinearGradient;
import android.graphics.Outline;
import android.graphics.Paint;
@@ -125,6 +126,9 @@
private static void sideShadow(Canvas canvas, Paint edgePaint,
RectF edgeShadowRect, float dx, float dy, int rotations) {
+ if (isRectEmpty(edgeShadowRect)) {
+ return;
+ }
int saved = canvas.save();
canvas.translate(dx, dy);
canvas.rotate(rotations * PERPENDICULAR_ANGLE);
@@ -153,4 +157,15 @@
canvas.drawPath(path, paint);
canvas.restoreToCount(saved);
}
+
+ /**
+ * Differs from {@link RectF#isEmpty()} as this first converts the rect to int and then checks.
+ * <p/>
+ * This is required because {@link Canvas_Delegate#native_drawRect(long, float, float, float,
+ * float, long)} casts the co-ordinates to int and we want to ensure that it doesn't end up
+ * drawing empty rectangles, which results in IllegalArgumentException.
+ */
+ private static boolean isRectEmpty(RectF rect) {
+ return (int) rect.left >= (int) rect.right || (int) rect.top >= (int) rect.bottom;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 4d2c2fc..c6d60f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -181,7 +181,7 @@
*/
private static LayoutLog sCurrentLog = sDefaultLog;
- private static final int LAST_SUPPORTED_FEATURE = Features.PREFERENCES_RENDERING;
+ private static final int LAST_SUPPORTED_FEATURE = Features.RENDER_ALL_DRAWABLE_STATES;
@Override
public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index e0f87fd..feb2590 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -86,11 +86,14 @@
}
@Override
- public Result render(long timeout) {
+ public Result render(long timeout, boolean forceMeasure) {
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(timeout);
if (mLastResult.isSuccess()) {
+ if (forceMeasure) {
+ mSession.invalidateRenderingSize();
+ }
mLastResult = mSession.render(false /*freshRender*/);
}
} finally {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3f553e7..2cbbeba 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -92,6 +92,8 @@
import java.util.List;
import java.util.Map;
+import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
+
/**
* Custom implementation of Context/Activity to handle non compiled resources.
*/
@@ -305,7 +307,7 @@
// check if this is a style resource
if (value instanceof StyleResourceValue) {
// get the id that will represent this style.
- outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value);
+ outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value);
return true;
}
@@ -783,6 +785,14 @@
}
+ @Override
+ public String getPackageName() {
+ if (mApplicationInfo.packageName == null) {
+ mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE);
+ }
+ return mApplicationInfo.packageName;
+ }
+
// ------------- private new methods
/**
@@ -1190,12 +1200,6 @@
}
@Override
- public String getPackageName() {
- // pass
- return null;
- }
-
- @Override
public String getBasePackageName() {
// pass
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
new file mode 100644
index 0000000..b98f96f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.RenderParams;
+import com.android.ide.common.rendering.api.SessionParams.Key;
+
+/**
+ * This contains all known keys for the {@link RenderParams#getFlag(Key)}.
+ * <p/>
+ * The IDE has its own copy of this class which may be newer or older than this one.
+ * <p/>
+ * Constants should never be modified or removed from this class.
+ */
+public final class RenderParamsFlags {
+
+ public static final Key<String> FLAG_KEY_ROOT_TAG =
+ new Key<String>("rootTag", String.class);
+ public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+ new Key<Boolean>("disableBitmapCaching", Boolean.class);
+ public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES =
+ new Key<Boolean>("renderAllDrawableStates", Boolean.class);
+ /**
+ * To tell LayoutLib that the IDE supports RecyclerView.
+ * <p/>
+ * Default is false.
+ */
+ public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
+ new Key<Boolean>("recyclerViewSupport", Boolean.class);
+ /**
+ * The application package name. Used via
+ * {@link com.android.ide.common.rendering.api.LayoutlibCallback#getFlag(Key)}
+ */
+ public static final Key<String> FLAG_KEY_APPLICATION_PACKAGE =
+ new Key<String>("applicationPackage", String.class);
+
+ // Disallow instances.
+ private RenderParamsFlags() {}
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
deleted file mode 100644
index 22b5192..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge.android;
-
-import com.android.ide.common.rendering.api.SessionParams;
-
-/**
- * This contains all known keys for the {@link SessionParams#getFlag(SessionParams.Key)}.
- * <p/>
- * The IDE has its own copy of this class which may be newer or older than this one.
- * <p/>
- * Constants should never be modified or removed from this class.
- */
-public final class SessionParamsFlags {
-
- public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
- new SessionParams.Key<String>("rootTag", String.class);
- public static final SessionParams.Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
- new SessionParams.Key<Boolean>("recyclerViewSupport", Boolean.class);
-
- // Disallow instances.
- private SessionParamsFlags() {}
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index aac5d33..e4c7288 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -23,15 +23,16 @@
import com.android.ide.common.rendering.api.SessionParams;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import android.content.Context;
import android.view.View;
-import android.widget.LinearLayout;
import java.lang.reflect.Method;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.*;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
/**
* Utility class for working with android.support.v7.widget.RecyclerView
@@ -39,17 +40,15 @@
@SuppressWarnings("SpellCheckingInspection") // for "recycler".
public class RecyclerViewUtil {
- /**
- * Used by {@link LayoutManagerType}.
- * <p/>
- * Not declared inside the enum, since it needs to be accessible in the constructor.
- */
- private static final Object CONTEXT = new Object();
-
- public static final String CN_RECYCLER_VIEW = "android.support.v7.widget.RecyclerView";
+ private static final String RV_PKG_PREFIX = "android.support.v7.widget.";
+ public static final String CN_RECYCLER_VIEW = RV_PKG_PREFIX + "RecyclerView";
private static final String CN_LAYOUT_MANAGER = CN_RECYCLER_VIEW + "$LayoutManager";
private static final String CN_ADAPTER = CN_RECYCLER_VIEW + "$Adapter";
+ // LinearLayoutManager related constants.
+ private static final String CN_LINEAR_LAYOUT_MANAGER = RV_PKG_PREFIX + "LinearLayoutManager";
+ private static final Class<?>[] LLM_CONSTRUCTOR_SIGNATURE = new Class<?>[]{Context.class};
+
/**
* Tries to create an Adapter ({@code android.support.v7.widget.RecyclerView.Adapter} and a
* LayoutManager {@code RecyclerView.LayoutManager} and assign these to the {@code RecyclerView}
@@ -71,39 +70,35 @@
private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
@NonNull LayoutlibCallback callback) throws ReflectionException {
- Object cookie = context.getCookie(recyclerView);
- assert cookie == null || cookie instanceof LayoutManagerType || cookie instanceof String;
- if (!(cookie instanceof LayoutManagerType)) {
- if (cookie != null) {
- // TODO: When layoutlib API is updated, try to load the class with a null
- // constructor or a constructor taking one argument - the context.
- Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
- "LayoutManager (" + cookie + ") not found, falling back to " +
- "LinearLayoutManager", null);
- }
- cookie = LayoutManagerType.getDefault();
+ if (getLayoutManager(recyclerView) == null) {
+ // Only set the layout manager if not already set by the recycler view.
+ Object layoutManager = createLayoutManager(context, callback);
+ setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
}
- Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback);
- setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
}
+ /** Creates a LinearLayoutManager using the provided context. */
@Nullable
- private static Object createLayoutManager(@Nullable LayoutManagerType type,
- @NonNull Context context, @NonNull LayoutlibCallback callback)
+ private static Object createLayoutManager(@NonNull Context context,
+ @NonNull LayoutlibCallback callback)
throws ReflectionException {
- if (type == null) {
- type = LayoutManagerType.getDefault();
- }
try {
- return callback.loadView(type.getClassName(), type.getSignature(), type.getArgs(context));
+ return callback.loadView(CN_LINEAR_LAYOUT_MANAGER, LLM_CONSTRUCTOR_SIGNATURE,
+ new Object[]{ context});
} catch (Exception e) {
throw new ReflectionException(e);
}
}
@Nullable
+ private static Object getLayoutManager(View recyclerview) throws ReflectionException {
+ Method getLayoutManager = getMethod(recyclerview.getClass(), "getLayoutManager");
+ return getLayoutManager != null ? invoke(getLayoutManager, recyclerview) : null;
+ }
+
+ @Nullable
private static Object createAdapter(@NonNull SessionParams params) throws ReflectionException {
- Boolean ideSupport = params.getFlag(SessionParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
+ Boolean ideSupport = params.getFlag(RenderParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
if (ideSupport != Boolean.TRUE) {
return null;
}
@@ -145,74 +140,4 @@
}
throw new RuntimeException("invalid object/classname combination.");
}
-
- /** Supported LayoutManagers. */
- public enum LayoutManagerType {
- LINEAR_LAYOUT_MANGER("Linear",
- "android.support.v7.widget.LinearLayoutManager",
- new Class[]{Context.class}, new Object[]{CONTEXT}),
- GRID_LAYOUT_MANAGER("Grid",
- "android.support.v7.widget.GridLayoutManager",
- new Class[]{Context.class, int.class}, new Object[]{CONTEXT, 2}),
- STAGGERED_GRID_LAYOUT_MANAGER("StaggeredGrid",
- "android.support.v7.widget.StaggeredGridLayoutManager",
- new Class[]{int.class, int.class}, new Object[]{2, LinearLayout.VERTICAL});
-
- private String mLogicalName;
- private String mClassName;
- private Class[] mSignature;
- private Object[] mArgs;
-
- LayoutManagerType(String logicalName, String className, Class[] signature, Object[] args) {
- mLogicalName = logicalName;
- mClassName = className;
- mSignature = signature;
- mArgs = args;
- }
-
- String getClassName() {
- return mClassName;
- }
-
- Class[] getSignature() {
- return mSignature;
- }
-
- @NonNull
- Object[] getArgs(Context context) {
- Object[] args = new Object[mArgs.length];
- System.arraycopy(mArgs, 0, args, 0, mArgs.length);
- for (int i = 0; i < args.length; i++) {
- if (args[i] == CONTEXT) {
- args[i] = context;
- }
- }
- return args;
- }
-
- @NonNull
- public static LayoutManagerType getDefault() {
- return LINEAR_LAYOUT_MANGER;
- }
-
- @Nullable
- public static LayoutManagerType getByLogicalName(@NonNull String logicalName) {
- for (LayoutManagerType type : values()) {
- if (logicalName.equals(type.mLogicalName)) {
- return type;
- }
- }
- return null;
- }
-
- @Nullable
- public static LayoutManagerType getByClassName(@NonNull String className) {
- for (LayoutManagerType type : values()) {
- if (className.equals(type.mClassName)) {
- return type;
- }
- }
- return null;
- }
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 9f9b968..dc89d0c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -74,7 +74,7 @@
}
public static String getTime(int platformVersion) {
- if (platformVersion == 0) {
+ if (isGreaterOrEqual(platformVersion, LOLLIPOP_MR1)) {
return "5:10";
}
if (platformVersion < GINGERBREAD) {
@@ -117,7 +117,7 @@
}
public static String getWifiIconType(int platformVersion) {
- return platformVersion == 0 ? "xml" : "png";
+ return isGreaterOrEqual(platformVersion, LOLLIPOP) ? "xml" : "png";
}
/**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9450b6c..04aadff 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -21,6 +21,10 @@
import org.xmlpull.v1.XmlPullParserException;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -29,6 +33,21 @@
/** Navigation bar background color attribute name. */
private static final String ATTR_COLOR = "navigationBarColor";
+ /**
+ * Constructor to be used when creating the {@link NavigationBar} as a regular control.
+ * This is currently used by the theme editor.
+ */
+ public NavigationBar(Context context, AttributeSet attrs)
+ throws XmlPullParserException {
+ this((BridgeContext) context,
+ Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+ LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+ ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+ View.LAYOUT_DIRECTION_RTL,
+ (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
+ context.getApplicationInfo().targetSdkVersion);
+ }
+
public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
boolean rtlEnabled, int simulatedPlatformVersion) throws XmlPullParserException {
super(context, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml",
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index e5f1f68..a0ed0e8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -25,7 +25,9 @@
import org.xmlpull.v1.XmlPullParserException;
+import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
@@ -39,7 +41,20 @@
private final int mSimulatedPlatformVersion;
/** Status bar background color attribute name. */
- private static final String ATTR_COLOR = "colorPrimaryDark";
+ private static final String ATTR_COLOR = "statusBarColor";
+
+ /**
+ * Constructor to be used when creating the {@link StatusBar} as a regular control. This
+ * is currently used by the theme editor.
+ */
+ public StatusBar(Context context, AttributeSet attrs) throws XmlPullParserException {
+ this((BridgeContext) context,
+ Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+ LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+ ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+ View.LAYOUT_DIRECTION_RTL,
+ context.getApplicationInfo().targetSdkVersion);
+ }
public StatusBar(BridgeContext context, Density density, int direction, boolean RtlEnabled,
int simulatedPlatformVersion) throws XmlPullParserException {
@@ -50,6 +65,7 @@
// FIXME: use FILL_H?
setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
+
int color = getThemeAttrColor(ATTR_COLOR, true);
setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 3a0321a..c34f9b5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -35,6 +35,7 @@
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
+import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
@@ -615,8 +616,22 @@
return;
}
- int width = layer.getImage().getWidth();
- int height = layer.getImage().getHeight();
+ int width;
+ int height;
+ Rectangle clipBounds = originalGraphics.getClipBounds();
+ if (clipBounds != null) {
+ if (clipBounds.width == 0 || clipBounds.height == 0) {
+ // Clip is 0 so no need to paint anything.
+ return;
+ }
+ // If we have clipBounds available, use them as they will always be
+ // smaller than the full layer size.
+ width = clipBounds.width;
+ height = clipBounds.height;
+ } else {
+ width = layer.getImage().getWidth();
+ height = layer.getImage().getHeight();
+ }
// Create a temporary image to which the color filter will be applied.
BufferedImage image = new BufferedImage(width, height,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 6513c5f..9e26502 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -22,12 +22,14 @@
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.resources.ResourceType;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
import android.view.AttachInfo_Accessor;
import android.view.View.MeasureSpec;
import android.widget.FrameLayout;
@@ -37,6 +39,10 @@
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
*
@@ -68,11 +74,37 @@
return Status.ERROR_NOT_A_DRAWABLE.createResult();
}
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+
+ final Boolean allStates =
+ params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES);
+ if (allStates == Boolean.TRUE) {
+ final List<BufferedImage> result;
+
+ if (d instanceof StateListDrawable) {
+ result = new ArrayList<BufferedImage>();
+ final StateListDrawable stateList = (StateListDrawable) d;
+ for (int i = 0; i < stateList.getStateCount(); i++) {
+ final Drawable stateDrawable = stateList.getStateDrawable(i);
+ result.add(renderImage(hardwareConfig, stateDrawable, context));
+ }
+ } else {
+ result = Collections.singletonList(renderImage(hardwareConfig, d, context));
+ }
+
+ return Status.SUCCESS.createResult(result);
+ } else {
+ BufferedImage image = renderImage(hardwareConfig, d, context);
+ return Status.SUCCESS.createResult(image);
+ }
+ }
+
+ private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d,
+ BridgeContext context) {
// create a simple FrameLayout
FrameLayout content = new FrameLayout(context);
// get the actual Drawable object to draw
- Drawable d = ResourceHelper.getDrawable(drawableResource, context);
content.setBackground(d);
// set the AttachInfo on the root view.
@@ -80,8 +112,27 @@
// measure
- int w = hardwareConfig.getScreenWidth();
- int h = hardwareConfig.getScreenHeight();
+ int w = d.getIntrinsicWidth();
+ int h = d.getIntrinsicHeight();
+
+ final int screenWidth = hardwareConfig.getScreenWidth();
+ final int screenHeight = hardwareConfig.getScreenHeight();
+
+ if (w == -1 || h == -1) {
+ // 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);
int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
content.measure(w_spec, h_spec);
@@ -105,8 +156,7 @@
// and draw
content.draw(canvas);
-
- return Status.SUCCESS.createResult(image);
+ return image;
}
protected BufferedImage getImage(int w, int h) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 95576ef..f6e5ef1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -45,7 +45,7 @@
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
@@ -403,7 +403,7 @@
// it can instantiate the custom Fragment.
Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
- String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG);
+ String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
boolean isPreference = "PreferenceScreen".equals(rootTag);
View view;
if (isPreference) {
@@ -554,7 +554,14 @@
// draw the views
// create the BufferedImage into which the layout will be rendered.
boolean newImage = false;
- if (newRenderSize || mCanvas == null) {
+
+ // When disableBitmapCaching is true, we do not reuse mImage and
+ // we create a new one in every render.
+ // This is useful when mImage is just a wrapper of Graphics2D so
+ // it doesn't get cached.
+ boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
+ RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+ if (newRenderSize || mCanvas == null || disableBitmapCaching) {
if (params.getImageFactory() != null) {
mImage = params.getImageFactory().getImage(
mMeasuredScreenWidth,
@@ -581,8 +588,12 @@
Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
true /*isMutable*/, hardwareConfig.getDensity());
- // create a Canvas around the Android bitmap
- mCanvas = new Canvas(bitmap);
+ if (mCanvas == null) {
+ // create a Canvas around the Android bitmap
+ mCanvas = new Canvas(bitmap);
+ } else {
+ mCanvas.setBitmap(bitmap);
+ }
mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
}
@@ -1064,7 +1075,7 @@
private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
boolean windowFullscreen = getBooleanThemeValue(resources,
- "windowFullscreen", false, !isThemeAppCompat(resources));
+ "windowFullscreen", false, true);
if (!windowFullscreen && !mWindowIsFloating) {
// default value
@@ -1199,15 +1210,15 @@
// between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
boolean isThemeAppCompat = false;
for (int i = 0; i < 50; i++) {
+ if (defaultTheme == null) {
+ break;
+ }
// for loop ensures that we don't run into cyclic theme inheritance.
if (defaultTheme.getName().startsWith("Theme.AppCompat")) {
isThemeAppCompat = true;
break;
}
defaultTheme = resources.getParent(defaultTheme);
- if (defaultTheme == null) {
- break;
- }
}
mIsThemeAppCompat = isThemeAppCompat;
}
@@ -1631,7 +1642,7 @@
return null;
}
- private void invalidateRenderingSize() {
+ public void invalidateRenderingSize() {
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
index d252462..8af93eb 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
index d109302..069f9f7 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
index 816ecc8..36e2688 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
index b034b75..ca438ad 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
index f86b1d3..a98abf5 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
index 8bbae90..7d8cc84 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
index 8af745d..7e6113b 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
new file mode 100644
index 0000000..c9b76be
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
new file mode 100644
index 0000000..2da2cb9
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
@@ -0,0 +1,393 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:ignore="HardcodedText,LabelFor,TextFields,ContentDescription,RtlHardcoded">
+
+ <FrameLayout
+ android:id="@id/frameLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginEnd="311dp">
+
+ <TextView
+ android:id="@id/textView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|top"
+ android:text="New Text" />
+ </FrameLayout>
+
+ <TextView
+ android:id="@id/textView2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/frameLayout"
+ android:text="Large Text"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@id/textView3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@id/textView2"
+ android:text="Medium Text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@id/textView4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/textView2"
+ android:layout_toEndOf="@id/textView2"
+ android:text="Small Text"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <Button
+ android:id="@id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/textView3"
+ android:layout_toEndOf="@id/textView4"
+ android:text="New Button" />
+
+ <Button
+ android:id="@id/button2"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@id/button"
+ android:text="New Button" />
+
+ <CheckBox
+ android:id="@id/checkBox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignEnd="@id/button"
+ android:layout_below="@id/button"
+ android:text="New CheckBox" />
+
+ <Switch
+ android:id="@id/switch1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/textView2"
+ android:text="New Switch" />
+
+ <ImageButton
+ android:id="@id/imageButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/button"
+ android:layout_toEndOf="@id/switch1" />
+
+ <ImageView
+ android:id="@id/imageView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_launcher"
+ android:layout_below="@id/button"
+ android:layout_toEndOf="@id/imageButton" />
+
+ <GridLayout
+ android:id="@id/gridLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/imageButton"
+ android:columnCount="2"
+ android:rowCount="2">
+
+ <ProgressBar
+ android:id="@id/progressBar"
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="0"
+ android:layout_row="0" />
+
+ <ProgressBar
+ android:id="@id/progressBar2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="1"
+ android:layout_row="0" />
+
+ <ProgressBar
+ android:id="@id/progressBar3"
+ style="?android:attr/progressBarStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="0"
+ android:layout_row="1" />
+
+ <ProgressBar
+ android:id="@id/progressBar4"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="1"
+ android:layout_row="1" />
+ </GridLayout>
+
+ <SeekBar
+ android:id="@id/seekBar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/gridLayout"
+ android:layout_toEndOf="@id/gridLayout" />
+
+ <RatingBar
+ android:id="@id/ratingBar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/switch2"
+ android:layout_toEndOf="@id/gridLayout" />
+
+ <Switch
+ android:id="@id/switch2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/seekBar"
+ android:layout_toEndOf="@id/switch1"
+ android:checked="true" />
+
+ <EditText
+ android:id="@id/editText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@id/ratingBar"
+ android:layout_alignParentStart="true"
+ android:text="plain text" />
+
+ <EditText
+ android:id="@id/editText2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/ratingBar"
+ android:ems="3"
+ android:inputType="textPersonName"
+ android:text="Name" />
+
+ <EditText
+ android:id="@id/editText3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/editText2"
+ android:ems="2"
+ android:inputType="textPassword"
+ android:text="password" />
+
+ <EditText
+ android:id="@id/editText4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/editText3"
+ android:layout_toEndOf="@id/editText3"
+ android:ems="3"
+ android:inputType="numberPassword"
+ android:text="numeric password" />
+
+ <EditText
+ android:id="@id/editText5"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/editText3"
+ android:layout_toStartOf="@id/editText6"
+ android:ems="7"
+ android:inputType="textEmailAddress"
+ android:text="email@domain.com" />
+
+ <EditText
+ android:id="@id/editText6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/editText4"
+ android:ems="7"
+ android:inputType="phone"
+ android:text="+11235554344" />
+
+ <EditText
+ android:id="@id/editText7"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/editText"
+ android:layout_toEndOf="@id/editText4"
+ android:ems="10"
+ android:inputType="textPostalAddress"
+ android:text="1600 Amphitheatre" />
+
+ <EditText
+ android:id="@id/editText9"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/editText5"
+ android:layout_alignParentStart="true"
+ android:ems="3"
+ android:inputType="time"
+ android:text="12:12" />
+
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/editText5"
+ android:layout_toEndOf="@id/editText9"
+ android:orientation="horizontal">
+
+ <RadioButton
+ android:id="@id/radioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="New RadioButton" />
+
+ <RadioButton
+ android:id="@id/radioButton2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="New RadioButton" />
+
+ </RadioGroup>
+
+ <CheckedTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="CheckedTextView"
+ android:id="@id/checkedTextView"
+ android:layout_below="@id/button2"
+ android:layout_alignParentEnd="true"
+ android:layout_alignStart="@id/button2" />
+
+ <DialerFilter
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/checkBox"
+ android:layout_toStartOf="@id/quickContactBadge"
+ android:id="@id/dialerFilter"
+ android:layout_above="@id/ratingBar"
+ android:layout_toEndOf="@id/seekBar">
+
+ <EditText
+ android:id="@android:id/hint"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Hint" />
+
+ <EditText
+ android:id="@android:id/primary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/hint"
+ android:text="Primary" />
+ </DialerFilter>
+
+ <QuickContactBadge
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/quickContactBadge"
+ android:layout_below="@id/checkedTextView"
+ android:layout_alignParentEnd="true" />
+
+ <android.inputmethodservice.ExtractEditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="ExtractEditText"
+ android:id="@id/extractEditText"
+ android:layout_below="@id/editText9"
+ android:layout_alignParentEnd="true"
+ android:layout_alignStart="@id/checkedTextView" />
+
+ <ZoomControls
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/zoomControls"
+ android:layout_below="@id/editText9"
+ android:layout_alignParentStart="true" />
+
+ <TextureView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/textureView"
+ android:layout_below="@id/zoomControls"
+ android:layout_alignParentStart="true"
+ android:layout_alignBottom="@id/extractEditText"
+ android:layout_toStartOf="@id/editText3" />
+
+ <ListView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/listView"
+ android:layout_below="@id/textureView"
+ android:layout_alignParentStart="true"
+ android:layout_alignEnd="@id/textureView" />
+
+ <GridView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/gridView"
+ android:layout_below="@id/extractEditText"
+ android:layout_alignParentEnd="true"
+ android:layout_alignStart="@id/extractEditText" />
+
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/scrollView"
+ android:layout_below="@id/zoomControls"
+ android:layout_toRightOf="@id/listView"
+ android:layout_toLeftOf="@id/extractEditText">
+
+ <TabHost
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@id/tabHost">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@id/linearLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"/>
+
+ <LinearLayout
+ android:id="@id/linearLayout2"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"/>
+
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+</ScrollView>
+
+ <SearchView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@id/searchView"
+ android:layout_alignBottom="@id/zoomControls"
+ android:layout_toEndOf="@id/seekBar" />
+
+</RelativeLayout>
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/ids.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/ids.xml
new file mode 100644
index 0000000..1dc2fa0
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/ids.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <item type="id" name="button" />
+ <item type="id" name="button2" />
+ <item type="id" name="checkBox" />
+ <item type="id" name="checkedTextView" />
+ <item type="id" name="dialerFilter" />
+ <item type="id" name="editText" />
+ <item type="id" name="editText2" />
+ <item type="id" name="editText3" />
+ <item type="id" name="editText4" />
+ <item type="id" name="editText5" />
+ <item type="id" name="editText6" />
+ <item type="id" name="editText7" />
+ <item type="id" name="editText8" />
+ <item type="id" name="editText9" />
+ <item type="id" name="extractEditText" />
+ <item type="id" name="frameLayout" />
+ <item type="id" name="gridLayout" />
+ <item type="id" name="gridView" />
+ <item type="id" name="imageButton" />
+ <item type="id" name="imageView" />
+ <item type="id" name="linearLayout" />
+ <item type="id" name="linearLayout2" />
+ <item type="id" name="listView" />
+ <item type="id" name="progressBar" />
+ <item type="id" name="progressBar2" />
+ <item type="id" name="progressBar3" />
+ <item type="id" name="progressBar4" />
+ <item type="id" name="quickContactBadge" />
+ <item type="id" name="radioButton" />
+ <item type="id" name="radioButton2" />
+ <item type="id" name="ratingBar" />
+ <item type="id" name="scrollView" />
+ <item type="id" name="searchView" />
+ <item type="id" name="seekBar" />
+ <item type="id" name="spinner" />
+ <item type="id" name="switch1" />
+ <item type="id" name="switch2" />
+ <item type="id" name="tabHost" />
+ <item type="id" name="textView" />
+ <item type="id" name="textView2" />
+ <item type="id" name="textView3" />
+ <item type="id" name="textView4" />
+ <item type="id" name="textureView" />
+ <item type="id" name="zoomControls" />
+</resources>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index ac23564..f2a039e 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -261,7 +261,7 @@
new ResourceRepository(new FolderWrapper(TEST_RES_DIR + APP_TEST_RES), false) {
@NonNull
@Override
- protected ResourceItem createResourceItem(String name) {
+ protected ResourceItem createResourceItem(@NonNull String name) {
return new ResourceItem(name);
}
};
@@ -275,14 +275,27 @@
ConfigGenerator.getEnumMap(attrs), getLayoutLog());
}
- /**
- * Create a new rendering session and test that rendering /layout/activity.xml on nexus 5
- * doesn't throw any exceptions.
- */
+ /** Text activity.xml */
@Test
- public void testRendering() throws ClassNotFoundException {
+ public void testActivity() throws ClassNotFoundException {
+ renderAndVerify("activity.xml", "activity.png");
+
+ }
+
+ /** Test allwidgets.xml */
+ @Test
+ public void testAllWidgets() throws ClassNotFoundException {
+ renderAndVerify("allwidgets.xml", "allwidgets.png");
+ }
+
+ /**
+ * Create a new rendering session and test that rendering given layout on nexus 5
+ * doesn't throw any exceptions and matches the provided image.
+ */
+ private void renderAndVerify(String layoutFileName, String goldenFileName)
+ throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/activity.xml");
+ LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
@@ -301,7 +314,7 @@
session.getResult().getErrorMessage());
}
try {
- String goldenImagePath = APP_TEST_DIR + "/golden/activity.png";
+ String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenFileName;
ImageUtils.requireSimilar(goldenImagePath, session.getImage());
} catch (IOException e) {
getLogger().error(e, e.getMessage());
@@ -309,7 +322,7 @@
}
/**
- * Uses Theme.Material and Target sdk version as 21.
+ * Uses Theme.Material and Target sdk version as 22.
*/
private SessionParams getSessionParams(LayoutPullParser layoutParser,
ConfigGenerator configGenerator, LayoutLibTestCallback layoutLibCallback) {
@@ -327,7 +340,7 @@
resourceResolver,
layoutLibCallback,
0,
- 21, // TODO: Make it more configurable to run tests for various versions.
+ 22, // TODO: Make it more configurable to run tests for various versions.
getLayoutLog());
}
@@ -381,17 +394,17 @@
}
@Override
- public void warning(String msgFormat, Object... args) {
+ public void warning(@NonNull String msgFormat, Object... args) {
failWithMsg(msgFormat, args);
}
@Override
- public void info(String msgFormat, Object... args) {
+ public void info(@NonNull String msgFormat, Object... args) {
// pass.
}
@Override
- public void verbose(String msgFormat, Object... args) {
+ public void verbose(@NonNull String msgFormat, Object... args) {
// pass.
}
};
@@ -399,7 +412,7 @@
return mLogger;
}
- private static void failWithMsg(String msgFormat, Object... args) {
- fail(msgFormat == null || args == null ? "" : String.format(msgFormat, args));
+ private static void failWithMsg(@NonNull String msgFormat, Object... args) {
+ fail(args == null ? "" : String.format(msgFormat, args));
}
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
index a5c3202..1191df6 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
@@ -21,12 +21,11 @@
import com.android.ide.common.resources.configuration.DensityQualifier;
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
-import com.android.ide.common.resources.configuration.LanguageQualifier;
import com.android.ide.common.resources.configuration.LayoutDirectionQualifier;
+import com.android.ide.common.resources.configuration.LocaleQualifier;
import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
import com.android.ide.common.resources.configuration.NetworkCodeQualifier;
import com.android.ide.common.resources.configuration.NightModeQualifier;
-import com.android.ide.common.resources.configuration.RegionQualifier;
import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
@@ -158,10 +157,9 @@
config.setUiModeQualifier(new UiModeQualifier(UiMode.NORMAL));
config.setNightModeQualifier(new NightModeQualifier(NightMode.NOTNIGHT));
config.setCountryCodeQualifier(new CountryCodeQualifier());
- config.setLanguageQualifier(new LanguageQualifier());
config.setLayoutDirectionQualifier(new LayoutDirectionQualifier());
config.setNetworkCodeQualifier(new NetworkCodeQualifier());
- config.setRegionQualifier(new RegionQualifier());
+ config.setLocaleQualifier(new LocaleQualifier());
config.setVersionQualifier(new VersionQualifier());
return config;
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index 0a5e798..5b648ef 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -23,8 +23,8 @@
import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.resources.ResourceType;
import com.android.ide.common.resources.IntArrayWrapper;
+import com.android.resources.ResourceType;
import com.android.util.Pair;
import com.android.utils.ILogger;
@@ -36,6 +36,8 @@
import com.google.android.collect.Maps;
+import static org.junit.Assert.fail;
+
@SuppressWarnings("deprecation") // For Pair
public class LayoutLibTestCallback extends LayoutlibCallback {
@@ -121,7 +123,7 @@
@Override
public ILayoutPullParser getParser(String layoutName) {
- org.junit.Assert.fail("This method shouldn't be called by this version of LayoutLib.");
+ fail("This method shouldn't be called by this version of LayoutLib.");
return null;
}