Merge "Change WindowState.mShownFrame to WindowState.mShownPosition."
diff --git a/api/current.txt b/api/current.txt
index 301878d..9fe6857 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2876,6 +2876,7 @@
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
     method public abstract long getStartDelay();
+    method public long getTotalDuration();
     method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
@@ -2891,6 +2892,7 @@
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final long DURATION_INFINITE = -1L; // 0xffffffffffffffffL
   }
 
   public static abstract interface Animator.AnimatorListener {
diff --git a/api/system-current.txt b/api/system-current.txt
index abafb35..5e1aa41 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2975,6 +2975,7 @@
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
     method public abstract long getStartDelay();
+    method public long getTotalDuration();
     method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
@@ -2990,6 +2991,7 @@
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final long DURATION_INFINITE = -1L; // 0xffffffffffffffffL
   }
 
   public static abstract interface Animator.AnimatorListener {
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index d331c2a..844063c 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -28,7 +28,6 @@
 
     /**
      * The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
-     * @hide
      */
     public static final long DURATION_INFINITE = -1;
     /**
@@ -191,11 +190,18 @@
     /**
      * Gets the total duration of the animation, accounting for animation sequences, start delay,
      * and repeating. Return {@link #DURATION_INFINITE} if the duration is infinite.
-     * @hide
-     * TODO: Unhide
+     *
+     * @return  Total time an animation takes to finish, starting from the time {@link #start()}
+     *          is called. {@link #DURATION_INFINITE} will be returned if the animation or any
+     *          child animation repeats infinite times.
      */
     public long getTotalDuration() {
-        return getStartDelay() + getDuration();
+        long duration = getDuration();
+        if (duration == DURATION_INFINITE) {
+            return DURATION_INFINITE;
+        } else {
+            return getStartDelay() + duration;
+        }
     }
 
     /**
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index d444638..1ab55dd 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1030,9 +1030,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         updateAnimatorsDuration();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 4b3df30..6f65889 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -536,9 +536,6 @@
         return mDuration;
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         if (mRepeatCount == INFINITE) {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 2a3756d..7747580 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -336,9 +336,6 @@
         return mUnscaledDuration;
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         return mUnscaledDuration + mUnscaledStartDelay;
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 11d0f4a..4ac547a 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -429,7 +429,8 @@
 
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
-                + " mSettingsActivityName=" + mSettingsActivityName);
+                + " mSettingsActivityName=" + mSettingsActivityName
+                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
         pw.println(prefix + "mIsDefaultResId=0x"
                 + Integer.toHexString(mIsDefaultResId));
         pw.println(prefix + "Service:");
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ab372d3..75ad916a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3705,13 +3705,14 @@
         }
 
         /**
-         * Returns true if the Window is free floating and has a shadow. Note that non overlapping
-         * windows do not have a shadow since it could not be seen anyways (a small screen / tablet
+         * Returns true if the Window is free floating and has a shadow (although at some times
+         * it might not be displaying it, e.g. during a resize). Note that non overlapping windows
+         * do not have a shadow since it could not be seen anyways (a small screen / tablet
          * "tiles" the windows side by side but does not overlap them).
          * @return Returns true when the window has a shadow created by the non client decor.
          **/
         private boolean windowHasShadow() {
-            return windowHasNonClientDecor() && getElevation() > 0;
+            return windowHasNonClientDecor() && nonClientDecorHasShadow(mWindow.mWorkspaceId);
         }
 
         void setWindow(PhoneWindow phoneWindow) {
@@ -5417,7 +5418,7 @@
      * @param workspaceId The Id of the workspace which contains this window.
      * @Return Returns true if the window should show a shadow.
      **/
-    private boolean nonClientDecorHasShadow(int workspaceId) {
+    private static boolean nonClientDecorHasShadow(int workspaceId) {
         return workspaceId == FREEFORM_WORKSPACE_STACK_ID;
     }
 
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 60f0502..9c420c2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -143,7 +143,7 @@
     <string name="fcError" msgid="3327560126588500777">"Forbindelsesproblemer eller ugyldig funktionskode."</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
     <string name="httpError" msgid="7956392511146698522">"Der opstod en netværksfejl."</string>
-    <string name="httpErrorLookup" msgid="4711687456111963163">"Webadressen kunne ikke findes."</string>
+    <string name="httpErrorLookup" msgid="4711687456111963163">"Webadressen blev ikke fundet."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Ordningen for webstedsgodkendelse understøttes ikke."</string>
     <string name="httpErrorAuth" msgid="1435065629438044534">"Der kunne ikke godkendes."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Godkendelse via proxyserveren mislykkedes."</string>
@@ -155,7 +155,7 @@
     <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Der kunne ikke oprettes en sikker forbindelse."</string>
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"Der kunne ikke fås adgang til filen."</string>
-    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Den ønskede fil kunne ikke findes."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Den ønskede fil blev ikke fundet."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Der behandles for mange anmodninger. Prøv igen senere."</string>
     <string name="notification_title" msgid="8967710025036163822">"Loginfejl for <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Synkroniser"</string>
@@ -248,7 +248,7 @@
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"undersøge indholdet i et vindue, du interagerer med."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"aktivere Udforsk ved berøring"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"De emner, der trykkes på, læses højt, og skærmen kan udforskes ved hjælp af bevægelser."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedrede webhjælpefunktioner"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Aktivér udvidede webhjælpefunktioner"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Der installeres muligvis scripts for at gøre appindhold mere tilgængeligt."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"observere tekst, du skriver"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c13ef14..54100d5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -223,7 +223,7 @@
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android系统"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"工作"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 049da2d..7164747 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -865,6 +865,47 @@
     }
 
     @SmallTest
+    public void testZeroScale() throws Throwable {
+        // Test whether animations would end properly when the scale is forced to be zero
+        float scale = ValueAnimator.getDurationScale();
+        ValueAnimator.setDurationScale(0f);
+
+        // Run two animators, one of which has a start delay, after setting the duration scale to 0
+        a1.setStartDelay(200);
+        final MyListener l1 =  new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.startCalled);
+                assertFalse(l2.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+
+                a1.start();
+                a2.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertTrue(l1.endCalled);
+                assertTrue(l2.endCalled);
+            }
+        });
+
+        // Restore duration scale
+        ValueAnimator.setDurationScale(scale);
+    }
+
+    @SmallTest
     public void testReverse() throws Throwable {
         // Prolong animators duration so that we can do multiple checks during their run
         final ValueAnimator a3 = ValueAnimator.ofInt(0, 100);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f914b20..d031165 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3215,6 +3215,11 @@
             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
+            if (profile == null) {
+                Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                setLockdownTracker(null);
+                return true;
+            }
             int user = UserHandle.getUserId(Binder.getCallingUid());
             synchronized(mVpns) {
                 setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),