Merge "Handle the case where no session exists" into oc-dev
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 4ffb2e2..fdf6d63 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -26,10 +26,13 @@
 import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.util.PropertiesMap;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.view.View;
 import android.view.ViewGroup;
 
 import java.awt.image.BufferedImage;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -42,7 +45,9 @@
  */
 public class BridgeRenderSession extends RenderSession {
 
+    @Nullable
     private final RenderSessionImpl mSession;
+    @NonNull
     private Result mLastResult;
 
     @Override
@@ -52,41 +57,44 @@
 
     @Override
     public BufferedImage getImage() {
-        return mSession.getImage();
+        return mSession != null ? mSession.getImage() :
+                new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
     }
 
     @Override
     public boolean isAlphaChannelImage() {
-        return mSession.isAlphaChannelImage();
+        return mSession != null && mSession.isAlphaChannelImage();
     }
 
     @Override
     public List<ViewInfo> getRootViews() {
-        return mSession.getViewInfos();
+        return mSession != null ? mSession.getViewInfos() : Collections.emptyList();
     }
 
     @Override
     public List<ViewInfo> getSystemRootViews() {
-        return mSession.getSystemViewInfos();
+        return mSession != null ? mSession.getSystemViewInfos() : Collections.emptyList();
     }
 
     @Override
     public Map<Object, PropertiesMap> getDefaultProperties() {
-        return mSession.getDefaultProperties();
+        return mSession != null ? mSession.getDefaultProperties() : Collections.emptyMap();
     }
 
     @Override
     public Result measure(long timeout) {
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(timeout);
-            if (mLastResult.isSuccess()) {
-                mSession.invalidateRenderingSize();
-                mLastResult = mSession.measure();
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(timeout);
+                if (mLastResult.isSuccess()) {
+                    mSession.invalidateRenderingSize();
+                    mLastResult = mSession.measure();
+                }
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -94,18 +102,20 @@
 
     @Override
     public Result render(long timeout, boolean forceMeasure) {
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(timeout);
-            if (mLastResult.isSuccess()) {
-                if (forceMeasure) {
-                    mSession.invalidateRenderingSize();
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(timeout);
+                if (mLastResult.isSuccess()) {
+                    if (forceMeasure) {
+                        mSession.invalidateRenderingSize();
+                    }
+                    mLastResult = mSession.render(false /*freshRender*/);
                 }
-                mLastResult = mSession.render(false /*freshRender*/);
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -114,16 +124,18 @@
     @Override
     public Result animate(Object targetObject, String animationName,
             boolean isFrameworkAnimation, IAnimationListener listener) {
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
-            if (mLastResult.isSuccess()) {
-                mLastResult = mSession.animate(targetObject, animationName, isFrameworkAnimation,
-                        listener);
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                if (mLastResult.isSuccess()) {
+                    mLastResult = mSession.animate(targetObject, animationName, isFrameworkAnimation,
+                            listener);
+                }
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -136,16 +148,18 @@
             throw new IllegalArgumentException("parentView is not a ViewGroup");
         }
 
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
-            if (mLastResult.isSuccess()) {
-                mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index,
-                        listener);
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                if (mLastResult.isSuccess()) {
+                    mLastResult =
+                            mSession.insertChild((ViewGroup) parentView, childXml, index, listener);
+                }
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -162,16 +176,18 @@
             throw new IllegalArgumentException("childView is not a View");
         }
 
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
-            if (mLastResult.isSuccess()) {
-                mLastResult = mSession.moveChild((ViewGroup) parentView, (View) childView, index,
-                        layoutParams, listener);
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                if (mLastResult.isSuccess()) {
+                    mLastResult = mSession.moveChild((ViewGroup) parentView, (View) childView, index,
+                            layoutParams, listener);
+                }
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -183,15 +199,17 @@
             throw new IllegalArgumentException("childView is not a View");
         }
 
-        try {
-            Bridge.prepareThread();
-            mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
-            if (mLastResult.isSuccess()) {
-                mLastResult = mSession.removeChild((View) childView, listener);
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                if (mLastResult.isSuccess()) {
+                    mLastResult = mSession.removeChild((View) childView, listener);
+                }
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
             }
-        } finally {
-            mSession.release();
-            Bridge.cleanupThread();
         }
 
         return mLastResult;
@@ -221,7 +239,7 @@
         }
     }
 
-    /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
+    /*package*/ BridgeRenderSession(@Nullable RenderSessionImpl scene, @NonNull Result lastResult) {
         mSession = scene;
         if (scene != null) {
             mSession.setScene(this);
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/BridgeRenderSessionTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/BridgeRenderSessionTest.java
new file mode 100644
index 0000000..63b9b43
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/BridgeRenderSessionTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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;
+
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.Result.Status;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class BridgeRenderSessionTest {
+    @Test
+    public void testNullSession() {
+        BridgeRenderSession renderSession = new BridgeRenderSession(null, Status.ERROR_UNKNOWN
+                .createResult("Test result"));
+
+        assertNotNull(renderSession.getImage());
+        assertNotNull(renderSession.getRootViews());
+        assertNotNull(renderSession.getSystemRootViews());
+        assertNotNull(renderSession.getDefaultProperties());
+    }
+}
\ 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 c83d2e4..eb264d65 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
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.intensive;
 
+import com.android.layoutlib.bridge.BridgeRenderSessionTest;
 import com.android.layoutlib.bridge.TestDelegates;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParserTest;
 import com.android.layoutlib.bridge.impl.LayoutParserWrapperTest;
@@ -34,7 +35,8 @@
 @SuiteClasses({
         RenderTests.class, LayoutParserWrapperTest.class,
         BridgeXmlBlockParserTest.class, BridgeXmlPullAttributesTest.class,
-        Matrix_DelegateTest.class, TestDelegates.class, PerformanceTests.class
+        Matrix_DelegateTest.class, TestDelegates.class, PerformanceTests.class,
+        BridgeRenderSessionTest.class
 })
 public class Main {
 }