Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +8 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; import com.android.ide.common.rendering.api.Result.Status; import com.android.ide.common.rendering.api.SessionParams; import com.android.layoutlib.bridge.android.RenderParamsFlags; import com.android.layoutlib.bridge.impl.RenderDrawable; import com.android.layoutlib.bridge.impl.RenderSessionImpl; import com.android.layoutlib.bridge.util.DynamicIdMap; Loading Loading @@ -408,7 +409,9 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { /** * Starts a layout session by inflating and rendering it. The method returns a * {@link RenderSession} on which further actions can be taken. * * <p/> * If {@link SessionParams} includes the {@link RenderParamsFlags#FLAG_DO_NOT_RENDER_ON_CREATE}, * this method will only inflate the layout but will NOT render it. * @param params the {@link SessionParams} object with all the information necessary to create * the scene. * @return a new {@link RenderSession} object that contains the result of the layout. Loading @@ -424,7 +427,10 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { lastResult = scene.init(params.getTimeout()); if (lastResult.isSuccess()) { lastResult = scene.inflate(); if (lastResult.isSuccess()) { boolean doNotRenderOnCreate = Boolean.TRUE.equals( params.getFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE)); if (lastResult.isSuccess() && !doNotRenderOnCreate) { lastResult = scene.render(true /*freshRender*/); } } Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,12 @@ public final class RenderParamsFlags { */ public static final Key<Boolean> FLAG_KEY_XML_FILE_PARSER_SUPPORT = new Key<Boolean>("xmlFileParser", Boolean.class); /** * To tell LayoutLib to not render when creating a new session. This allows controlling when the first * layout rendering will happen. */ public static final Key<Boolean> FLAG_DO_NOT_RENDER_ON_CREATE = new Key<Boolean>("doNotRenderOnCreate", Boolean.class); // Disallow instances. private RenderParamsFlags() {} Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +39 −20 Original line number Diff line number Diff line Loading @@ -266,6 +266,34 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { mElapsedFrameTimeNanos = nanos; } /** * Renders the given view hierarchy to the passed canvas and returns the result of the render * operation. * @param canvas an optional canvas to render the views to. If null, only the measure and * layout steps will be executed. */ private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot, @Nullable Canvas canvas, int width, int height) { // measure again with the size we need // This must always be done before the call to layout measureView(viewRoot, null /*measuredView*/, width, MeasureSpec.EXACTLY, height, MeasureSpec.EXACTLY); // now do the layout. viewRoot.layout(0, 0, width, height); handleScrolling(context, viewRoot); if (canvas == null) { return SUCCESS.createResult(); } AttachInfo_Accessor.dispatchOnPreDraw(viewRoot); viewRoot.draw(canvas); return SUCCESS.createResult(); } /** * Renders the scene. * <p> Loading Loading @@ -367,24 +395,12 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } // measure again with the size we need // This must always be done before the call to layout measureView(mViewRoot, null /*measuredView*/, mMeasuredScreenWidth, MeasureSpec.EXACTLY, mMeasuredScreenHeight, MeasureSpec.EXACTLY); // now do the layout. mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); handleScrolling(mViewRoot); Result renderResult = SUCCESS.createResult(); if (params.isLayoutOnly()) { // delete the canvas and image to reset them on the next full rendering mImage = null; mCanvas = null; } else { AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot); // draw the views // create the BufferedImage into which the layout will be rendered. boolean newImage = false; Loading Loading @@ -446,6 +462,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { if (mElapsedFrameTimeNanos >= 0) { long initialTime = System_Delegate.nanoTime(); if (!mFirstFrameExecuted) { // We need to run an initial draw call to initialize the animations render(getContext(), mViewRoot, mCanvas, 0, 0); // The first frame will initialize the animations Choreographer_Delegate.doFrame(initialTime); mFirstFrameExecuted = true; Loading @@ -453,14 +472,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // Second frame will move the animations Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos); } mViewRoot.draw(mCanvas); renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth, mMeasuredScreenHeight); } mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false); // success! return SUCCESS.createResult(); return renderResult; } catch (Throwable e) { // get the real cause of the exception. Throwable t = e; Loading Loading @@ -488,7 +508,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { * @return the measured width/height if measuredView is non-null, null otherwise. */ @SuppressWarnings("deprecation") // For the use of Pair private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView, private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView, int width, int widthMode, int height, int heightMode) { int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode); int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode); Loading Loading @@ -1061,8 +1081,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { * the component supports nested scrolling attempt that first, then use the unconsumed scroll * part to scroll the content in the component. */ private void handleScrolling(View view) { BridgeContext context = getContext(); private static void handleScrolling(BridgeContext context, View view) { int scrollPosX = context.getScrollXPos(view); int scrollPosY = context.getScrollYPos(view); if (scrollPosX != 0 || scrollPosY != 0) { Loading @@ -1080,7 +1099,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } if (scrollPosX != 0 || scrollPosY != 0) { view.scrollBy(scrollPosX, scrollPosY); view.scrollTo(scrollPosX, scrollPosY); } } Loading @@ -1090,7 +1109,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { ViewGroup group = (ViewGroup) view; for (int i = 0; i < group.getChildCount(); i++) { View child = group.getChildAt(i); handleScrolling(child); handleScrolling(context, child); } } Loading tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml +4 −4 Original line number Diff line number Diff line Loading @@ -2,8 +2,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:scrollX="10px" android:scrollY="30px"> android:scrollX="30px" android:scrollY="90px"> <LinearLayout android:layout_width="60dp" android:layout_height="60dp" Loading @@ -29,8 +29,8 @@ android:layout_width="200dp" android:layout_height="400dp" android:orientation="vertical" android:scrollX="-30px" android:scrollY="150px"> android:scrollX="-90px" android:scrollY="450px"> <LinearLayout android:layout_width="fill_parent" android:layout_height="60dp" Loading tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +4 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.io.FolderWrapper; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.RenderParamsFlags; import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.impl.DelegateManager; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; Loading Loading @@ -564,7 +565,7 @@ public class Main { sFrameworkRepo.getConfiguredResources(config), themeName, isProjectTheme); return new SessionParams( SessionParams sessionParams = new SessionParams( layoutParser, renderingMode, null /*used for caching*/, Loading @@ -574,6 +575,8 @@ public class Main { 0, targetSdk, getLayoutLog()); sessionParams.setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true); return sessionParams; } private static LayoutLog getLayoutLog() { Loading Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +8 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; import com.android.ide.common.rendering.api.Result.Status; import com.android.ide.common.rendering.api.SessionParams; import com.android.layoutlib.bridge.android.RenderParamsFlags; import com.android.layoutlib.bridge.impl.RenderDrawable; import com.android.layoutlib.bridge.impl.RenderSessionImpl; import com.android.layoutlib.bridge.util.DynamicIdMap; Loading Loading @@ -408,7 +409,9 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { /** * Starts a layout session by inflating and rendering it. The method returns a * {@link RenderSession} on which further actions can be taken. * * <p/> * If {@link SessionParams} includes the {@link RenderParamsFlags#FLAG_DO_NOT_RENDER_ON_CREATE}, * this method will only inflate the layout but will NOT render it. * @param params the {@link SessionParams} object with all the information necessary to create * the scene. * @return a new {@link RenderSession} object that contains the result of the layout. Loading @@ -424,7 +427,10 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { lastResult = scene.init(params.getTimeout()); if (lastResult.isSuccess()) { lastResult = scene.inflate(); if (lastResult.isSuccess()) { boolean doNotRenderOnCreate = Boolean.TRUE.equals( params.getFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE)); if (lastResult.isSuccess() && !doNotRenderOnCreate) { lastResult = scene.render(true /*freshRender*/); } } Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,12 @@ public final class RenderParamsFlags { */ public static final Key<Boolean> FLAG_KEY_XML_FILE_PARSER_SUPPORT = new Key<Boolean>("xmlFileParser", Boolean.class); /** * To tell LayoutLib to not render when creating a new session. This allows controlling when the first * layout rendering will happen. */ public static final Key<Boolean> FLAG_DO_NOT_RENDER_ON_CREATE = new Key<Boolean>("doNotRenderOnCreate", Boolean.class); // Disallow instances. private RenderParamsFlags() {} Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +39 −20 Original line number Diff line number Diff line Loading @@ -266,6 +266,34 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { mElapsedFrameTimeNanos = nanos; } /** * Renders the given view hierarchy to the passed canvas and returns the result of the render * operation. * @param canvas an optional canvas to render the views to. If null, only the measure and * layout steps will be executed. */ private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot, @Nullable Canvas canvas, int width, int height) { // measure again with the size we need // This must always be done before the call to layout measureView(viewRoot, null /*measuredView*/, width, MeasureSpec.EXACTLY, height, MeasureSpec.EXACTLY); // now do the layout. viewRoot.layout(0, 0, width, height); handleScrolling(context, viewRoot); if (canvas == null) { return SUCCESS.createResult(); } AttachInfo_Accessor.dispatchOnPreDraw(viewRoot); viewRoot.draw(canvas); return SUCCESS.createResult(); } /** * Renders the scene. * <p> Loading Loading @@ -367,24 +395,12 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } // measure again with the size we need // This must always be done before the call to layout measureView(mViewRoot, null /*measuredView*/, mMeasuredScreenWidth, MeasureSpec.EXACTLY, mMeasuredScreenHeight, MeasureSpec.EXACTLY); // now do the layout. mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); handleScrolling(mViewRoot); Result renderResult = SUCCESS.createResult(); if (params.isLayoutOnly()) { // delete the canvas and image to reset them on the next full rendering mImage = null; mCanvas = null; } else { AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot); // draw the views // create the BufferedImage into which the layout will be rendered. boolean newImage = false; Loading Loading @@ -446,6 +462,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { if (mElapsedFrameTimeNanos >= 0) { long initialTime = System_Delegate.nanoTime(); if (!mFirstFrameExecuted) { // We need to run an initial draw call to initialize the animations render(getContext(), mViewRoot, mCanvas, 0, 0); // The first frame will initialize the animations Choreographer_Delegate.doFrame(initialTime); mFirstFrameExecuted = true; Loading @@ -453,14 +472,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // Second frame will move the animations Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos); } mViewRoot.draw(mCanvas); renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth, mMeasuredScreenHeight); } mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false); // success! return SUCCESS.createResult(); return renderResult; } catch (Throwable e) { // get the real cause of the exception. Throwable t = e; Loading Loading @@ -488,7 +508,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { * @return the measured width/height if measuredView is non-null, null otherwise. */ @SuppressWarnings("deprecation") // For the use of Pair private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView, private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView, int width, int widthMode, int height, int heightMode) { int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode); int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode); Loading Loading @@ -1061,8 +1081,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { * the component supports nested scrolling attempt that first, then use the unconsumed scroll * part to scroll the content in the component. */ private void handleScrolling(View view) { BridgeContext context = getContext(); private static void handleScrolling(BridgeContext context, View view) { int scrollPosX = context.getScrollXPos(view); int scrollPosY = context.getScrollYPos(view); if (scrollPosX != 0 || scrollPosY != 0) { Loading @@ -1080,7 +1099,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } if (scrollPosX != 0 || scrollPosY != 0) { view.scrollBy(scrollPosX, scrollPosY); view.scrollTo(scrollPosX, scrollPosY); } } Loading @@ -1090,7 +1109,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { ViewGroup group = (ViewGroup) view; for (int i = 0; i < group.getChildCount(); i++) { View child = group.getChildAt(i); handleScrolling(child); handleScrolling(context, child); } } Loading
tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml +4 −4 Original line number Diff line number Diff line Loading @@ -2,8 +2,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:scrollX="10px" android:scrollY="30px"> android:scrollX="30px" android:scrollY="90px"> <LinearLayout android:layout_width="60dp" android:layout_height="60dp" Loading @@ -29,8 +29,8 @@ android:layout_width="200dp" android:layout_height="400dp" android:orientation="vertical" android:scrollX="-30px" android:scrollY="150px"> android:scrollX="-90px" android:scrollY="450px"> <LinearLayout android:layout_width="fill_parent" android:layout_height="60dp" Loading
tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +4 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.io.FolderWrapper; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.RenderParamsFlags; import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.impl.DelegateManager; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; Loading Loading @@ -564,7 +565,7 @@ public class Main { sFrameworkRepo.getConfiguredResources(config), themeName, isProjectTheme); return new SessionParams( SessionParams sessionParams = new SessionParams( layoutParser, renderingMode, null /*used for caching*/, Loading @@ -574,6 +575,8 @@ public class Main { 0, targetSdk, getLayoutLog()); sessionParams.setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true); return sessionParams; } private static LayoutLog getLayoutLog() { Loading