Separate measure so it can only run inflate if needed

This allows to only do inflate + measure and not to render.

Change-Id: I4be08513728b656f699e9115e14cf618d95b538a
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 e0d8249..3ac1889 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -192,7 +192,9 @@
 
     @Override
     public void setElapsedFrameTimeNanos(long nanos) {
-        mSession.setElapsedFrameTimeNanos(nanos);
+        if (mSession != null) {
+            mSession.setElapsedFrameTimeNanos(nanos);
+        }
     }
 
     @Override
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 3ef568c..834ad74 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
@@ -134,6 +134,7 @@
     private List<ViewInfo> mViewInfoList;
     private List<ViewInfo> mSystemViewInfoList;
     private Layout.Builder mLayoutBuilder;
+    private boolean mNewRenderSize;
 
     private static final class PostInflateException extends Exception {
         private static final long serialVersionUID = 1L;
@@ -200,6 +201,88 @@
     }
 
     /**
+     * Measures the the current layout if needed (see {@link #invalidateRenderingSize}).
+     */
+    private void measure(@NonNull SessionParams params) {
+        // only do the screen measure when needed.
+        if (mMeasuredScreenWidth != -1) {
+            return;
+        }
+
+        RenderingMode renderingMode = params.getRenderingMode();
+        HardwareConfig hardwareConfig = params.getHardwareConfig();
+
+        mNewRenderSize = true;
+        mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
+        mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
+
+        if (renderingMode != RenderingMode.NORMAL) {
+            int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
+                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+                    : MeasureSpec.EXACTLY;
+            int heightMeasureSpecMode = renderingMode.isVertExpand() ?
+                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+                    : MeasureSpec.EXACTLY;
+
+            // We used to compare the measured size of the content to the screen size but
+            // this does not work anymore due to the 2 following issues:
+            // - If the content is in a decor (system bar, title/action bar), the root view
+            //   will not resize even with the UNSPECIFIED because of the embedded layout.
+            // - If there is no decor, but a dialog frame, then the dialog padding prevents
+            //   comparing the size of the content to the screen frame (as it would not
+            //   take into account the dialog padding).
+
+            // The solution is to first get the content size in a normal rendering, inside
+            // the decor or the dialog padding.
+            // Then measure only the content with UNSPECIFIED to see the size difference
+            // and apply this to the screen size.
+
+            // first measure the full layout, with EXACTLY to get the size of the
+            // content as it is inside the decor/dialog
+            @SuppressWarnings("deprecation")
+            Pair<Integer, Integer> exactMeasure = measureView(
+                    mViewRoot, mContentRoot.getChildAt(0),
+                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
+                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
+
+            // now measure the content only using UNSPECIFIED (where applicable, based on
+            // the rendering mode). This will give us the size the content needs.
+            @SuppressWarnings("deprecation")
+            Pair<Integer, Integer> result = measureView(
+                    mContentRoot, mContentRoot.getChildAt(0),
+                    mMeasuredScreenWidth, widthMeasureSpecMode,
+                    mMeasuredScreenHeight, heightMeasureSpecMode);
+
+            // now look at the difference and add what is needed.
+            if (renderingMode.isHorizExpand()) {
+                int measuredWidth = exactMeasure.getFirst();
+                int neededWidth = result.getFirst();
+                if (neededWidth > measuredWidth) {
+                    mMeasuredScreenWidth += neededWidth - measuredWidth;
+                }
+                if (mMeasuredScreenWidth < measuredWidth) {
+                    // If the screen width is less than the exact measured width,
+                    // expand to match.
+                    mMeasuredScreenWidth = measuredWidth;
+                }
+            }
+
+            if (renderingMode.isVertExpand()) {
+                int measuredHeight = exactMeasure.getSecond();
+                int neededHeight = result.getSecond();
+                if (neededHeight > measuredHeight) {
+                    mMeasuredScreenHeight += neededHeight - measuredHeight;
+                }
+                if (mMeasuredScreenHeight < measuredHeight) {
+                    // If the screen height is less than the exact measured height,
+                    // expand to match.
+                    mMeasuredScreenHeight = measuredHeight;
+                }
+            }
+        }
+    }
+
+    /**
      * Inflates the layout.
      * <p>
      * {@link #acquire(long)} must have been called before this.
@@ -245,6 +328,14 @@
 
             setActiveToolbar(view, context, params);
 
+            measure(params);
+            measureView(mViewRoot, null /*measuredView*/,
+                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
+                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
+            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+                    false);
+
             return SUCCESS.createResult();
         } catch (PostInflateException e) {
             return ERROR_INFLATION.createResult(e.getMessage(), e);
@@ -320,82 +411,9 @@
                 return ERROR_NOT_INFLATED.createResult();
             }
 
-            RenderingMode renderingMode = params.getRenderingMode();
+            measure(params);
+
             HardwareConfig hardwareConfig = params.getHardwareConfig();
-
-            // only do the screen measure when needed.
-            boolean newRenderSize = false;
-            if (mMeasuredScreenWidth == -1) {
-                newRenderSize = true;
-                mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
-                mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
-
-                if (renderingMode != RenderingMode.NORMAL) {
-                    int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
-                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
-                            : MeasureSpec.EXACTLY;
-                    int heightMeasureSpecMode = renderingMode.isVertExpand() ?
-                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
-                            : MeasureSpec.EXACTLY;
-
-                    // We used to compare the measured size of the content to the screen size but
-                    // this does not work anymore due to the 2 following issues:
-                    // - If the content is in a decor (system bar, title/action bar), the root view
-                    //   will not resize even with the UNSPECIFIED because of the embedded layout.
-                    // - If there is no decor, but a dialog frame, then the dialog padding prevents
-                    //   comparing the size of the content to the screen frame (as it would not
-                    //   take into account the dialog padding).
-
-                    // The solution is to first get the content size in a normal rendering, inside
-                    // the decor or the dialog padding.
-                    // Then measure only the content with UNSPECIFIED to see the size difference
-                    // and apply this to the screen size.
-
-                    // first measure the full layout, with EXACTLY to get the size of the
-                    // content as it is inside the decor/dialog
-                    @SuppressWarnings("deprecation")
-                    Pair<Integer, Integer> exactMeasure = measureView(
-                            mViewRoot, mContentRoot.getChildAt(0),
-                            mMeasuredScreenWidth, MeasureSpec.EXACTLY,
-                            mMeasuredScreenHeight, MeasureSpec.EXACTLY);
-
-                    // now measure the content only using UNSPECIFIED (where applicable, based on
-                    // the rendering mode). This will give us the size the content needs.
-                    @SuppressWarnings("deprecation")
-                    Pair<Integer, Integer> result = measureView(
-                            mContentRoot, mContentRoot.getChildAt(0),
-                            mMeasuredScreenWidth, widthMeasureSpecMode,
-                            mMeasuredScreenHeight, heightMeasureSpecMode);
-
-                    // now look at the difference and add what is needed.
-                    if (renderingMode.isHorizExpand()) {
-                        int measuredWidth = exactMeasure.getFirst();
-                        int neededWidth = result.getFirst();
-                        if (neededWidth > measuredWidth) {
-                            mMeasuredScreenWidth += neededWidth - measuredWidth;
-                        }
-                        if (mMeasuredScreenWidth < measuredWidth) {
-                            // If the screen width is less than the exact measured width,
-                            // expand to match.
-                            mMeasuredScreenWidth = measuredWidth;
-                        }
-                    }
-
-                    if (renderingMode.isVertExpand()) {
-                        int measuredHeight = exactMeasure.getSecond();
-                        int neededHeight = result.getSecond();
-                        if (neededHeight > measuredHeight) {
-                            mMeasuredScreenHeight += neededHeight - measuredHeight;
-                        }
-                        if (mMeasuredScreenHeight < measuredHeight) {
-                            // If the screen height is less than the exact measured height,
-                            // expand to match.
-                            mMeasuredScreenHeight = measuredHeight;
-                        }
-                    }
-                }
-            }
-
             Result renderResult = SUCCESS.createResult();
             if (params.isLayoutOnly()) {
                 // delete the canvas and image to reset them on the next full rendering
@@ -412,7 +430,8 @@
                 // it doesn't get cached.
                 boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
                     RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
-                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
+                if (mNewRenderSize || mCanvas == null || disableBitmapCaching) {
+                    mNewRenderSize = false;
                     if (params.getImageFactory() != null) {
                         mImage = params.getImageFactory().getImage(
                                 mMeasuredScreenWidth,