Merge "Fix ninepatch scaling." into mnc-ub-dev
diff --git a/Android.mk b/Android.mk
index 99e0c46..92d6d8b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -669,6 +669,16 @@
   $(fwbase_dirs_to_document) \
 	$(non_base_dirs)
 
+###########################################################
+## Return all directories that have a 'NO_DOCS' file in
+## them, appending a '%' to them to form a pattern to
+## filter out files under those directories.
+## $(1): A list of base directories to look at.
+###########################################################
+define find-no-docs-pattern
+$(addsuffix %, $(dir $(foreach dir, $(1), $(shell cd $(LOCAL_PATH); find $(dir) -name NO_DOCS))))
+endef
+
 # These are relative to frameworks/base
 # FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
 dirs_to_document := \
@@ -676,6 +686,9 @@
   $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
   $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) \
 
+patterns_to_not_document := \
+	$(call find-no-docs-pattern, $(dirs_to_document))
+
 # These are relative to frameworks/base
 html_dirs := \
 	$(FRAMEWORKS_BASE_SUBDIRS) \
@@ -689,7 +702,7 @@
 
 # These are relative to frameworks/base
 framework_docs_LOCAL_SRC_FILES := \
-	$(call find-other-java-files, $(dirs_to_document)) \
+	$(filter-out $(patterns_to_not_document), $(call find-other-java-files, $(dirs_to_document))) \
 	$(common_src_files)
 
 # These are relative to frameworks/base
diff --git a/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java b/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java
deleted file mode 100644
index 78aedc5..0000000
--- a/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java
+++ /dev/null
@@ -1,52 +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 android.animation;
-
-/**
- * A fake implementation of Animator which doesn't do anything.
- */
-public class FakeAnimator extends Animator {
-    @Override
-    public long getStartDelay() {
-        return 0;
-    }
-
-    @Override
-    public void setStartDelay(long startDelay) {
-
-    }
-
-    @Override
-    public Animator setDuration(long duration) {
-        return this;
-    }
-
-    @Override
-    public long getDuration() {
-        return 0;
-    }
-
-    @Override
-    public void setInterpolator(TimeInterpolator value) {
-
-    }
-
-    @Override
-    public boolean isRunning() {
-        return false;
-    }
-}
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index 4603b63..54021c9 100644
--- a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -16,9 +16,16 @@
 
 package android.animation;
 
+import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Delegate implementing the native methods of android.animation.PropertyValuesHolder
  *
@@ -29,81 +36,161 @@
  * around to map int to instance of the delegate.
  *
  * The main goal of this class' methods are to provide a native way to access setters and getters
- * on some object. In this case we want to default to using Java reflection instead so the native
- * methods do nothing.
+ * on some object. We override these methods to use reflection since the original reflection
+ * implementation of the PropertyValuesHolder won't be able to access protected methods.
  *
  */
-/*package*/ class PropertyValuesHolder_Delegate {
+/*package*/
+@SuppressWarnings("unused")
+class PropertyValuesHolder_Delegate {
+    // This code is copied from android.animation.PropertyValuesHolder and must be kept in sync
+    // We try several different types when searching for appropriate setter/getter functions.
+    // The caller may have supplied values in a type that does not match the setter/getter
+    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
+    // Also, the use of generics in constructors means that we end up with the Object versions
+    // of primitive types (Float vs. float). But most likely, the setter/getter functions
+    // will take primitive types instead.
+    // So we supply an ordered array of other types to try before giving up.
+    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
+            Double.class, Integer.class};
+    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
+            Float.class, Double.class};
+
+    private static final Object sMethodIndexLock = new Object();
+    private static final Map<Long, Method> ID_TO_METHOD = new HashMap<Long, Method>();
+    private static final Map<String, Long> METHOD_NAME_TO_ID = new HashMap<String, Long>();
+    private static long sNextId = 1;
+
+    private static long registerMethod(Class<?> targetClass, String methodName, Class[] types,
+            int nArgs) {
+        // Encode the number of arguments in the method name
+        String methodIndexName = String.format("%1$s#%2$d", methodName, nArgs);
+        synchronized (sMethodIndexLock) {
+            Long methodId = METHOD_NAME_TO_ID.get(methodIndexName);
+
+            if (methodId != null) {
+                // The method was already registered
+                return methodId;
+            }
+
+            Class[] args = new Class[nArgs];
+            Method method = null;
+            for (Class typeVariant : types) {
+                for (int i = 0; i < nArgs; i++) {
+                    args[i] = typeVariant;
+                }
+                try {
+                    method = targetClass.getDeclaredMethod(methodName, args);
+                } catch (NoSuchMethodException ignore) {
+                }
+            }
+
+            if (method != null) {
+                methodId = sNextId++;
+                ID_TO_METHOD.put(methodId, method);
+                METHOD_NAME_TO_ID.put(methodIndexName, methodId);
+
+                return methodId;
+            }
+        }
+
+        // Method not found
+        return 0;
+    }
+
+    private static void callMethod(Object target, long methodID, Object... args) {
+        Method method = ID_TO_METHOD.get(methodID);
+        assert method != null;
+
+        try {
+            method.setAccessible(true);
+            method.invoke(target, args);
+        } catch (IllegalAccessException e) {
+            Bridge.getLog().error(null, "Unable to update property during animation", e, null);
+        } catch (InvocationTargetException e) {
+            Bridge.getLog().error(null, "Unable to update property during animation", e, null);
+        }
+    }
 
     @LayoutlibDelegate
     /*package*/ static long nGetIntMethod(Class<?> targetClass, String methodName) {
-        // return 0 to force PropertyValuesHolder to use Java reflection.
-        return 0;
+        return nGetMultipleIntMethod(targetClass, methodName, 1);
     }
 
     @LayoutlibDelegate
     /*package*/ static long nGetFloatMethod(Class<?> targetClass, String methodName) {
-        // return 0 to force PropertyValuesHolder to use Java reflection.
-        return 0;
+        return nGetMultipleFloatMethod(targetClass, methodName, 1);
     }
 
     @LayoutlibDelegate
     /*package*/ static long nGetMultipleIntMethod(Class<?> targetClass, String methodName,
             int numParams) {
-        // TODO: return the right thing.
-        return 0;
+        return registerMethod(targetClass, methodName, INTEGER_VARIANTS, numParams);
     }
 
     @LayoutlibDelegate
     /*package*/ static long nGetMultipleFloatMethod(Class<?> targetClass, String methodName,
             int numParams) {
-        // TODO: return the right thing.
-        return 0;
+        return registerMethod(targetClass, methodName, FLOAT_VARIANTS, numParams);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallIntMethod(Object target, long methodID, int arg) {
-        // do nothing
+        callMethod(target, methodID, arg);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallFloatMethod(Object target, long methodID, float arg) {
-        // do nothing
+        callMethod(target, methodID, arg);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallTwoIntMethod(Object target, long methodID, int arg1,
             int arg2) {
-        // do nothing
+        callMethod(target, methodID, arg1, arg2);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallFourIntMethod(Object target, long methodID, int arg1,
             int arg2, int arg3, int arg4) {
-        // do nothing
+        callMethod(target, methodID, arg1, arg2, arg3, arg4);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallMultipleIntMethod(Object target, long methodID,
             int[] args) {
-        // do nothing
+        assert args != null;
+
+        // Box parameters
+        Object[] params = new Object[args.length];
+        for (int i = 0; i < args.length; i++) {
+            params[i] = args;
+        }
+        callMethod(target, methodID, params);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallTwoFloatMethod(Object target, long methodID, float arg1,
             float arg2) {
-        // do nothing
+        callMethod(target, methodID, arg1, arg2);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallFourFloatMethod(Object target, long methodID, float arg1,
             float arg2, float arg3, float arg4) {
-        // do nothing
+        callMethod(target, methodID, arg1, arg2, arg3, arg4);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nCallMultipleFloatMethod(Object target, long methodID,
             float[] args) {
-        // do nothing
+        assert args != null;
+
+        // Box parameters
+        Object[] params = new Object[args.length];
+        for (int i = 0; i < args.length; i++) {
+            params[i] = args;
+        }
+        callMethod(target, methodID, params);
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 31dd3d9..db4c6dc6 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -327,12 +327,19 @@
             return null;
         }
 
-        // let the framework inflate the ColorStateList from the XML file.
-        File f = new File(value);
-        if (f.isFile()) {
-            try {
-                XmlPullParser parser = ParserFactory.create(f);
 
+        try {
+            // Get the state list file content from callback to parse PSI file
+            XmlPullParser parser = mContext.getLayoutlibCallback().getXmlFileParser(value);
+            if (parser == null) {
+                // If used with a version of Android Studio that does not implement getXmlFileParser
+                // fall back to reading the file from disk
+                File f = new File(value);
+                if (f.isFile()) {
+                    parser = ParserFactory.create(f);
+                }
+            }
+            if (parser != null) {
                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                         parser, mContext, resValue.isFramework());
                 try {
@@ -341,18 +348,18 @@
                 } finally {
                     blockParser.ensurePopped();
                 }
-            } catch (XmlPullParserException e) {
-                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to configure parser for " + value, e, null);
-                return null;
-            } catch (Exception e) {
-                // this is an error and not warning since the file existence is checked before
-                // attempting to parse it.
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                        "Failed to parse file " + value, e, null);
-
-                return null;
             }
+        } catch (XmlPullParserException e) {
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                    "Failed to configure parser for " + value, e, null);
+            return null;
+        } catch (Exception e) {
+            // this is an error and not warning since the file existence is checked before
+            // attempting to parse it.
+            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+                    "Failed to parse file " + value, e, null);
+
+            return null;
         }
 
         try {
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
index dd2978f..3c71233 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
@@ -44,7 +44,7 @@
 
     // ---- delegate data ----
     // This governs how accurate the approximation of the Path is.
-    private static final float PRECISION = 0.002f;
+    private static final float PRECISION = 0.0002f;
 
     /**
      * Array containing the path points components. There are three components for each point:
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
index 5f0d98b..9677aaf 100644
--- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -18,6 +18,7 @@
 
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.java.System_Delegate;
 
 /**
  * Delegate implementing the native methods of android.os.SystemClock
@@ -30,9 +31,6 @@
  *
  */
 public class SystemClock_Delegate {
-    private static long sBootTime = System.currentTimeMillis();
-    private static long sBootTimeNano = System.nanoTime();
-
     /**
      * Returns milliseconds since boot, not counting time spent in deep sleep.
      * <b>Note:</b> This value may get reset occasionally (before it would
@@ -42,7 +40,7 @@
      */
     @LayoutlibDelegate
     /*package*/ static long uptimeMillis() {
-        return System.currentTimeMillis() - sBootTime;
+        return System_Delegate.currentTimeMillis() - System_Delegate.bootTimeMillis();
     }
 
     /**
@@ -52,7 +50,7 @@
      */
     @LayoutlibDelegate
     /*package*/ static long elapsedRealtime() {
-        return System.currentTimeMillis() - sBootTime;
+        return System_Delegate.currentTimeMillis() - System_Delegate.bootTimeMillis();
     }
 
     /**
@@ -62,7 +60,7 @@
      */
     @LayoutlibDelegate
     /*package*/ static long elapsedRealtimeNanos() {
-        return System.nanoTime() - sBootTimeNano;
+        return System_Delegate.nanoTime() - System_Delegate.bootTime();
     }
 
     /**
@@ -72,7 +70,7 @@
      */
     @LayoutlibDelegate
     /*package*/ static long currentThreadTimeMillis() {
-        return System.currentTimeMillis();
+        return System_Delegate.currentTimeMillis();
     }
 
     /**
@@ -84,7 +82,7 @@
      */
     @LayoutlibDelegate
     /*package*/ static long currentThreadTimeMicro() {
-        return System.currentTimeMillis() * 1000;
+        return System_Delegate.currentTimeMillis() * 1000;
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
index f75ee50..01af669 100644
--- a/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
@@ -17,6 +17,8 @@
 
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 /**
  * Delegate used to provide new implementation of a select few methods of {@link Choreographer}
  *
@@ -25,9 +27,41 @@
  *
  */
 public class Choreographer_Delegate {
+    static final AtomicReference<Choreographer> mInstance = new AtomicReference<Choreographer>();
+
+    @LayoutlibDelegate
+    public static Choreographer getInstance() {
+        if (mInstance.get() == null) {
+            mInstance.compareAndSet(null, Choreographer.getInstance_Original());
+        }
+
+        return mInstance.get();
+    }
 
     @LayoutlibDelegate
     public static float getRefreshRate() {
         return 60.f;
     }
+
+    @LayoutlibDelegate
+    static void scheduleVsyncLocked(Choreographer thisChoreographer) {
+        // do nothing
+    }
+
+    public static void doFrame(long frameTimeNanos) {
+        Choreographer thisChoreographer = Choreographer.getInstance();
+
+        thisChoreographer.mLastFrameTimeNanos = frameTimeNanos;
+
+        thisChoreographer.mFrameInfo.markInputHandlingStart();
+        thisChoreographer.doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+
+        thisChoreographer.mFrameInfo.markAnimationsStart();
+        thisChoreographer.doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+
+        thisChoreographer.mFrameInfo.markPerformTraversalsStart();
+        thisChoreographer.doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+
+        thisChoreographer.doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+    }
 }
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 48ca7d8..c8e3d03 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -183,7 +183,7 @@
      */
     private static LayoutLog sCurrentLog = sDefaultLog;
 
-    private static final int LAST_SUPPORTED_FEATURE = Features.RECYCLER_VIEW_ADAPTER;
+    private static final int LAST_SUPPORTED_FEATURE = Features.THEME_PREVIEW_NAVIGATION_BAR;
 
     @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 feb2590..2ac212c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -23,6 +23,7 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.tools.layoutlib.java.System_Delegate;
 
 import android.view.View;
 import android.view.ViewGroup;
@@ -191,6 +192,21 @@
     }
 
     @Override
+    public void setSystemTimeNanos(long nanos) {
+        System_Delegate.setNanosTime(nanos);
+    }
+
+    @Override
+    public void setSystemBootTimeNanos(long nanos) {
+        System_Delegate.setBootTimeNanos(nanos);
+    }
+
+    @Override
+    public void setElapsedFrameTimeNanos(long nanos) {
+        mSession.setElapsedFrameTimeNanos(nanos);
+    }
+
+    @Override
     public void dispose() {
     }
 
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 9c89bfe2..dfbc69b 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
@@ -19,9 +19,6 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.Density;
 
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -41,29 +38,18 @@
     private static final int WIDTH_DEFAULT = 36;
     private static final int WIDTH_SW360 = 40;
     private static final int WIDTH_SW600 = 48;
-    private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+    protected static final String LAYOUT_XML = "/bars/navigation_bar.xml";
     private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
 
-
-    /**
-     * Constructor to be used when creating the {@link NavigationBar} as a regular control.
-     * This is currently used by the theme editor.
-     */
-    @SuppressWarnings("unused")
-    public NavigationBar(Context context, AttributeSet attrs) {
-        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,
-                0);
+    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion) {
+        this(context, density, orientation, isRtl, rtlEnabled, simulatedPlatformVersion,
+          getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML);
     }
 
-    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
-            boolean rtlEnabled, int simulatedPlatformVersion) {
-        super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
-                "navigation_bar.xml", simulatedPlatformVersion);
+    protected NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion, String layoutPath) {
+        super(context, orientation, layoutPath, "navigation_bar.xml", simulatedPlatformVersion);
 
         int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
         setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -117,7 +103,7 @@
         view.setLayoutParams(layoutParams);
     }
 
-    private static int getSidePadding(float sw) {
+    protected int getSidePadding(float sw) {
         if (sw >= 400) {
             return PADDING_WIDTH_SW400;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
new file mode 100644
index 0000000..0435280
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.bars;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Navigation Bar for the Theme Editor preview.
+ *
+ * For small bars, it is identical to {@link NavigationBar}.
+ * But wide bars from {@link NavigationBar} are too wide for the Theme Editor preview.
+ * To solve that problem, {@link ThemePreviewNavigationBar} use the layout for small bars,
+ * and have no padding on the sides. That way, they have a similar look as the true ones,
+ * and they fit in the Theme Editor preview.
+ */
+public class ThemePreviewNavigationBar extends NavigationBar {
+    private static final int PADDING_WIDTH_SW600 = 0;
+
+    @SuppressWarnings("unused")
+    public ThemePreviewNavigationBar(Context context, AttributeSet attrs) {
+        super((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,
+                0, LAYOUT_XML);
+    }
+
+    @Override
+    protected int getSidePadding(float sw) {
+        if (sw >= 600) {
+            return PADDING_WIDTH_SW600;
+        }
+        return super.getSidePadding(sw);
+    }
+}
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 26f9000..d797eeca 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
@@ -42,10 +42,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
  *
@@ -72,8 +68,12 @@
         BridgeContext context = getContext();
         drawableResource = context.getRenderResources().resolveResValue(drawableResource);
 
-        if (drawableResource == null ||
-                drawableResource.getResourceType() != ResourceType.DRAWABLE) {
+        if (drawableResource == null) {
+            return Status.ERROR_NOT_A_DRAWABLE.createResult();
+        }
+
+        ResourceType resourceType = drawableResource.getResourceType();
+        if (resourceType != ResourceType.DRAWABLE && resourceType != ResourceType.MIPMAP) {
             return Status.ERROR_NOT_A_DRAWABLE.createResult();
         }
 
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 0ffa357..ec50cfe 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
@@ -46,6 +46,7 @@
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
 import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.util.Pair;
 
 import android.animation.AnimationThread;
@@ -62,6 +63,7 @@
 import android.preference.Preference_Delegate;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
+import android.view.Choreographer_Delegate;
 import android.view.IWindowManager;
 import android.view.IWindowManagerImpl;
 import android.view.Surface;
@@ -120,6 +122,10 @@
     private int mMeasuredScreenWidth = -1;
     private int mMeasuredScreenHeight = -1;
     private boolean mIsAlphaChannelImage;
+    /** If >= 0, a frame will be executed */
+    private long mElapsedFrameTimeNanos = -1;
+    /** True if one frame has been already executed to start the animations */
+    private boolean mFirstFrameExecuted = false;
 
     // information being returned through the API
     private BufferedImage mImage;
@@ -252,6 +258,14 @@
     }
 
     /**
+     * Sets the time for which the next frame will be selected. The time is the elapsed time from
+     * the current system nanos time. You
+     */
+    public void setElapsedFrameTimeNanos(long nanos) {
+        mElapsedFrameTimeNanos = nanos;
+    }
+
+    /**
      * Renders the scene.
      * <p>
      * {@link #acquire(long)} must have been called before this.
@@ -428,6 +442,16 @@
                     gc.dispose();
                 }
 
+                if (mElapsedFrameTimeNanos >= 0) {
+                    long initialTime = System_Delegate.nanoTime();
+                    if (!mFirstFrameExecuted) {
+                        // The first frame will initialize the animations
+                        Choreographer_Delegate.doFrame(initialTime);
+                        mFirstFrameExecuted = true;
+                    }
+                    // Second frame will move the animations
+                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
+                }
                 mViewRoot.draw(mCanvas);
             }
 
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
new file mode 100644
index 0000000..9f26627
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
new file mode 100644
index 0000000..89009be
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/indeterminate_progressbar.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/indeterminate_progressbar.xml
new file mode 100644
index 0000000..70d7396
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/indeterminate_progressbar.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:padding="16dp"
+              android:orientation="horizontal"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent">
+
+    <ProgressBar
+             android:layout_height="fill_parent"
+             android:layout_width="fill_parent" />
+
+</LinearLayout>
+
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 64aedb9..dea86bf 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
@@ -48,6 +48,8 @@
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import static org.junit.Assert.fail;
 
@@ -353,16 +355,46 @@
         renderAndVerify(params, "expand_horz_layout.png");
     }
 
+    /** Test expand_layout.xml */
+    @Test
+    public void testVectorAnimation() throws ClassNotFoundException {
+        // Create the layout pull parser.
+        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
+                "indeterminate_progressbar.xml");
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+        layoutLibCallback.initResources();
+
+        SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                RenderingMode.V_SCROLL, 22);
+
+        renderAndVerify(params, "animated_vector.png", TimeUnit.SECONDS.toNanos(2));
+
+        parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
+                "indeterminate_progressbar.xml");
+        params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                RenderingMode.V_SCROLL, 22);
+        renderAndVerify(params, "animated_vector_1.png", TimeUnit.SECONDS.toNanos(3));
+    }
+
     /**
      * Create a new rendering session and test that rendering given layout on nexus 5
      * doesn't throw any exceptions and matches the provided image.
+     * <p/>If frameTimeNanos is >= 0 a frame will be executed during the rendering. The time
+     * indicates how far in the future is.
      */
-    private void renderAndVerify(SessionParams params, String goldenFileName)
+    private void renderAndVerify(SessionParams params, String goldenFileName, long frameTimeNanos)
             throws ClassNotFoundException {
         // TODO: Set up action bar handler properly to test menu rendering.
         // Create session params.
         RenderSession session = sBridge.createSession(params);
 
+        if (frameTimeNanos != -1) {
+            session.setElapsedFrameTimeNanos(frameTimeNanos);
+        }
+
         if (!session.getResult().isSuccess()) {
             getLogger().error(session.getResult().getException(),
                     session.getResult().getErrorMessage());
@@ -385,6 +417,15 @@
      * 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(SessionParams params, String goldenFileName)
+            throws ClassNotFoundException {
+        renderAndVerify(params, goldenFileName, -1);
+    }
+
+    /**
+     * 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 {
         renderAndVerify(layoutFileName, goldenFileName, ConfigGenerator.NEXUS_5);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index c209793..558a914 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -175,7 +175,9 @@
         "android.text.format.DateFormat#is24HourFormat",
         "android.text.Hyphenator#getSystemHyphenatorLocation",
         "android.util.Xml#newPullParser",
+        "android.view.Choreographer#getInstance",
         "android.view.Choreographer#getRefreshRate",
+        "android.view.Choreographer#scheduleVsyncLocked",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.Display#getWindowManager",
         "android.view.LayoutInflater#rInflate",
@@ -299,6 +301,7 @@
         };
 
     private final static String[] PROMOTED_FIELDS = new String[] {
+        "android.view.Choreographer#mLastFrameTimeNanos",
         "android.widget.SimpleMonthView#mTitle",
         "android.widget.SimpleMonthView#mCalendar",
         "android.widget.SimpleMonthView#mDayOfWeekLabelCalendar"
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
index 0b85c48..5e47261 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -134,7 +134,33 @@
             }
         });
 
-        // Case 5: java.util.LinkedHashMap.eldest()
+        // Case 5: java.lang.System time calls
+        METHOD_REPLACERS.add(new MethodReplacer() {
+            @Override
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+                return JAVA_LANG_SYSTEM.equals(owner) && name.equals("nanoTime");
+            }
+
+            @Override
+            public void replace(MethodInformation mi) {
+                mi.name = "nanoTime";
+                mi.owner = Type.getInternalName(System_Delegate.class);
+            }
+        });
+        METHOD_REPLACERS.add(new MethodReplacer() {
+            @Override
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+                return JAVA_LANG_SYSTEM.equals(owner) && name.equals("currentTimeMillis");
+            }
+
+            @Override
+            public void replace(MethodInformation mi) {
+                mi.name = "currentTimeMillis";
+                mi.owner = Type.getInternalName(System_Delegate.class);
+            }
+        });
+
+        // Case 6: java.util.LinkedHashMap.eldest()
         METHOD_REPLACERS.add(new MethodReplacer() {
 
             private final String VOID_TO_MAP_ENTRY =
@@ -157,7 +183,7 @@
             }
         });
 
-        // Case 6: android.content.Context.getClassLoader() in LayoutInflater
+        // Case 7: android.content.Context.getClassLoader() in LayoutInflater
         METHOD_REPLACERS.add(new MethodReplacer() {
             // When LayoutInflater asks for a class loader, we must return the class loader that
             // cannot return app's custom views/classes. This is so that in case of any failure
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/System_Delegate.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/System_Delegate.java
index 613c8d9..be93744 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/System_Delegate.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/System_Delegate.java
@@ -18,12 +18,22 @@
 
 import com.android.tools.layoutlib.create.ReplaceMethodCallsAdapter;
 
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
 /**
  * Provides dummy implementation of methods that don't exist on the host VM.
+ * This also providers a time control that allows to set a specific system time.
  *
  * @see ReplaceMethodCallsAdapter
  */
+@SuppressWarnings("unused")
 public class System_Delegate {
+    // Current system time
+    private static AtomicLong mNanosTime = new AtomicLong(System.nanoTime());
+    // Time that the system booted up in nanos
+    private static AtomicLong mBootNanosTime = new AtomicLong(System.nanoTime());
+
     public static void log(String message) {
         // ignore.
     }
@@ -31,4 +41,28 @@
     public static void log(String message, Throwable th) {
         // ignore.
     }
+
+    public static void setNanosTime(long nanos) {
+        mNanosTime.set(nanos);
+    }
+
+    public static void setBootTimeNanos(long nanos) {
+        mBootNanosTime.set(nanos);
+    }
+
+    public static long nanoTime() {
+        return mNanosTime.get();
+    }
+
+    public static long currentTimeMillis() {
+        return TimeUnit.NANOSECONDS.toMillis(mNanosTime.get());
+    }
+
+    public static long bootTime() {
+        return mBootNanosTime.get();
+    }
+
+    public static long bootTimeMillis() {
+        return TimeUnit.NANOSECONDS.toMillis(mBootNanosTime.get());
+    }
 }