Merge "Load up-to-date thumbnail if the cached one is out of date."
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4a8203b..0cc44e7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -58,6 +58,7 @@
 import android.view.Gravity;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
 
@@ -3202,11 +3203,14 @@
 
             bindNotificationHeader(contentView);
             bindLargeIcon(contentView);
+            boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
             if (title != null) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
                 contentView.setTextViewText(R.id.title, title);
+                contentView.setViewLayoutWidth(R.id.title, showProgress
+                        ? ViewGroup.LayoutParams.WRAP_CONTENT
+                        : ViewGroup.LayoutParams.MATCH_PARENT);
             }
-            boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
             if (text != null) {
                 int textId = showProgress ? com.android.internal.R.id.text_line_1
                         : com.android.internal.R.id.text;
diff --git a/docs/html/images/testing/test_framework.png b/docs/html/images/testing/test_framework.png
deleted file mode 100644
index fbc5fc2..0000000
--- a/docs/html/images/testing/test_framework.png
+++ /dev/null
Binary files differ
diff --git a/libs/common_time/common_time_server_api.cpp b/libs/common_time/common_time_server_api.cpp
index e0f35a9..60e6567 100644
--- a/libs/common_time/common_time_server_api.cpp
+++ b/libs/common_time/common_time_server_api.cpp
@@ -285,7 +285,7 @@
     if (res > 0)                                  \
         write(fd, buffer, res);                   \
 } while (0)
-#define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b))
+#define checked_percentage(a, b) ((0 == (b)) ? 0.0f : ((100.0f * (a)) / (b)))
 
 status_t CommonTimeServer::dumpClockInterface(int fd,
                                               const Vector<String16>& /* args */,
diff --git a/libs/common_time/common_time_server_packets.cpp b/libs/common_time/common_time_server_packets.cpp
index 9833c37..c7c893d 100644
--- a/libs/common_time/common_time_server_packets.cpp
+++ b/libs/common_time/common_time_server_packets.cpp
@@ -48,12 +48,12 @@
 #define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl)
 #define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq)
 
-#define DESERIALIZE_FIELD(field_name, type, converter)      \
-    do {                                                    \
-        if ((offset + sizeof(field_name)) > length)         \
-            return -1;                                      \
-        field_name = converter(*((type*)(data + offset)));  \
-        offset += sizeof(field_name);                       \
+#define DESERIALIZE_FIELD(field_name, type, converter)       \
+    do {                                                     \
+        if ((offset + sizeof(field_name)) > length)          \
+            return -1;                                       \
+        (field_name) = converter(*((type*)(data + offset))); \
+        offset += sizeof(field_name);                        \
     } while (0)
 #define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs)
 #define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl)
diff --git a/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
index 201f47d..36df924 100644
--- a/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
+++ b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
@@ -19,6 +19,7 @@
         android:layout_height="wrap_content"
         android:focusable="true"
         android:focusableInTouchMode="true"
+        android:contentDescription="@string/status_bar_recent_inspect_item_title"
         android:layout_gravity="center"
         android:layout_centerInParent="true"
         android:clipToPadding="false"
@@ -49,6 +50,7 @@
             android:layout_gravity="center_horizontal"
             android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
             android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
+            android:contentDescription="@string/status_bar_accessibility_dismiss_recents"
             android:alpha="@integer/dismiss_unselected_alpha"
             android:src="@drawable/recents_tv_dismiss_icon" />
     <TextView
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 658571e..2c8a559 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -53,8 +53,7 @@
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
-            android:layout_marginBottom="@dimen/close_handle_underlap"
-            android:importantForAccessibility="no" />
+            android:layout_marginBottom="@dimen/close_handle_underlap" />
 
         <ViewStub
             android:id="@+id/keyguard_user_switcher"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 25a7266..ab3675a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -34,6 +34,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -47,6 +48,8 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
@@ -336,6 +339,7 @@
     private boolean mFadingOut;
     private boolean mParentFadingOut;
     private boolean mGroupExpandedForMeasure;
+    private boolean mScrollable;
     private View mForcedScroll;
     private float mBackgroundFadeAmount = 1.0f;
     private static final Property<NotificationStackScrollLayout, Float> BACKGROUND_FADE =
@@ -443,7 +447,6 @@
 
     private void initView(Context context) {
         mScroller = new OverScroller(getContext());
-        setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setClipChildren(false);
         final ViewConfiguration configuration = ViewConfiguration.get(context);
@@ -1725,6 +1728,15 @@
             }
         }
         mContentHeight = height + mTopPadding;
+        updateScrollability();
+    }
+
+    private void updateScrollability() {
+        boolean scrollable = getScrollRange() > 0;
+        if (scrollable != mScrollable) {
+            mScrollable = scrollable;
+            setFocusable(scrollable);
+        }
     }
 
     private void updateBackground() {
@@ -3522,6 +3534,68 @@
         mPhoneStatusBar.requestNotificationUpdate();
     }
 
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
+        event.setScrollable(mScrollable);
+        event.setScrollX(mScrollX);
+        event.setScrollY(mOwnScrollY);
+        event.setMaxScrollX(mScrollX);
+        event.setMaxScrollY(getScrollRange());
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
+        final int scrollRange = getScrollRange();
+        if (scrollRange > 0) {
+            info.setScrollable(true);
+            if (mScrollY > 0) {
+                info.addAction(
+                        AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
+            }
+            if (mScrollY < scrollRange) {
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
+            return true;
+        }
+        if (!isEnabled()) {
+            return false;
+        }
+        int direction = -1;
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+                // fall through
+            case android.R.id.accessibilityActionScrollDown:
+                direction = 1;
+                // fall through
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+                // fall through
+            case android.R.id.accessibilityActionScrollUp:
+                final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
+                        - mBottomStackPeekSize - mBottomStackSlowDownHeight;
+                final int targetScrollY = Math.max(0,
+                        Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
+                if (targetScrollY != mOwnScrollY) {
+                    mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScrollY - mOwnScrollY);
+                    postInvalidateOnAnimation();
+                    return true;
+                }
+                break;
+        }
+        return false;
+    }
+
     @Override
     public void onGroupsChanged() {
         mPhoneStatusBar.requestNotificationUpdate();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index 3f95427..de2c58c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -44,4 +44,19 @@
             mImpl.setSafeMode(isSafeMode());
         }
     }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
+        mImpl.onUserUnlocked(userHandle);
+    }
+
+    @Override
+    public void onStopUser(int userHandle) {
+        mImpl.onUserStopped(userHandle);
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        mImpl.reloadWidgetsMaskedStateForGroup(userHandle);
+    }
 }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index ac2dda3..4e0ddd6 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -158,12 +158,6 @@
 
             if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 onConfigurationChanged();
-            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
-                onUserUnlocked(userId);
-            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                onUserStopped(userId);
-            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                reloadWidgetsMaskedStateForGroup(userId);
             } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
                     || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
                 synchronized (mLock) {
@@ -281,13 +275,6 @@
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
                 sdFilter, null, null);
 
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
-        userFilter.addAction(Intent.ACTION_USER_STOPPED);
-        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                userFilter, null, null);
-
         IntentFilter offModeFilter = new IntentFilter();
         offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
         offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -454,7 +441,7 @@
      * due to user not being available and package suspension.
      * userId must be the group parent.
      */
-    private void reloadWidgetsMaskedStateForGroup(int userId) {
+    void reloadWidgetsMaskedStateForGroup(int userId) {
         if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
             return;
         }
@@ -2525,7 +2512,7 @@
         }
     }
 
-    private void onUserUnlocked(int userId) {
+    void onUserUnlocked(int userId) {
         if (isProfileWithLockedParent(userId)) {
             return;
         }
@@ -3072,7 +3059,7 @@
         return new AtomicFile(settingsFile);
     }
 
-    private void onUserStopped(int userId) {
+    void onUserStopped(int userId) {
         synchronized (mLock) {
             boolean crossProfileWidgetsChanged = false;
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index c26520e..05823b5 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -262,7 +262,7 @@
             TetherInterfaceStateMachine sm = mIfaces.get(iface);
             if (up) {
                 if (sm == null) {
-                    sm = new TetherInterfaceStateMachine(iface, mLooper, usb, mPublicSync,
+                    sm = new TetherInterfaceStateMachine(iface, mLooper, usb,
                             mNMService, mStatsService, this);
                     mIfaces.put(iface, sm);
                     sm.start();
@@ -338,7 +338,7 @@
                 if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
                 return;
             }
-            sm = new TetherInterfaceStateMachine(iface, mLooper, usb, mPublicSync,
+            sm = new TetherInterfaceStateMachine(iface, mLooper, usb,
                     mNMService, mStatsService, this);
             mIfaces.put(iface, sm);
             sm.start();
@@ -576,38 +576,39 @@
 
     public int tether(String iface) {
         if (DBG) Log.d(TAG, "Tethering " + iface);
-        TetherInterfaceStateMachine sm = null;
         synchronized (mPublicSync) {
-            sm = mIfaces.get(iface);
+            TetherInterfaceStateMachine sm = mIfaces.get(iface);
+            if (sm == null) {
+                Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
+                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+            }
+            // Ignore the error status of the interface.  If the interface is available,
+            // the errors are referring to past tethering attempts anyway.
+            if (!sm.isAvailable()) {
+                Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
+                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+
+            }
+            sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
+            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
         }
-        if (sm == null) {
-            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
-            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-        }
-        if (!sm.isAvailable() && !sm.isErrored()) {
-            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
-            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-        }
-        sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
-        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
     }
 
     public int untether(String iface) {
         if (DBG) Log.d(TAG, "Untethering " + iface);
-        TetherInterfaceStateMachine sm = null;
         synchronized (mPublicSync) {
-            sm = mIfaces.get(iface);
+            TetherInterfaceStateMachine sm = mIfaces.get(iface);
+            if (sm == null) {
+                Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
+                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+            }
+            if (!sm.isTethered()) {
+                Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
+                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+            }
+            sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
         }
-        if (sm == null) {
-            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
-            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-        }
-        if (sm.isErrored()) {
-            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
-            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-        }
-        sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
     }
 
     public void untetherAll() {
@@ -618,9 +619,8 @@
     }
 
     public int getLastTetherError(String iface) {
-        TetherInterfaceStateMachine sm = null;
         synchronized (mPublicSync) {
-            sm = mIfaces.get(iface);
+            TetherInterfaceStateMachine sm = mIfaces.get(iface);
             if (sm == null) {
                 Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
                         ", ignoring");
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 875fc60..0dc910d 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -84,13 +84,10 @@
     private final boolean mUsb;
     private final String mIfaceName;
 
-    private final Object mMutex;  // Protects the fields below.
-    private boolean mAvailable;
-    private boolean mTethered;
     private int mLastError;
     private String mMyUpstreamIfaceName;  // may change over time
 
-    public TetherInterfaceStateMachine(String ifaceName, Looper looper, boolean usb, Object mutex,
+    public TetherInterfaceStateMachine(String ifaceName, Looper looper, boolean usb,
                     INetworkManagementService nMService, INetworkStatsService statsService,
                     IControlsTethering tetherController) {
         super(ifaceName, looper);
@@ -99,7 +96,6 @@
         mTetherController = tetherController;
         mIfaceName = ifaceName;
         mUsb = usb;
-        mMutex = mutex;
         setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
 
         mInitialState = new InitialState();
@@ -127,53 +123,31 @@
     }
 
     public int getLastError() {
-        synchronized (mMutex) {
-            return mLastError;
-        }
+        return mLastError;
     }
 
     private void setLastError(int error) {
-        synchronized (mMutex) {
-            mLastError = error;
+        mLastError = error;
 
-            if (isErrored()) {
-                if (mUsb) {
-                    // note everything's been unwound by this point so nothing to do on
-                    // further error..
-                    configureUsbIface(false, mIfaceName);
-                }
+        if (isErrored()) {
+            if (mUsb) {
+                // note everything's been unwound by this point so nothing to do on
+                // further error..
+                configureUsbIface(false, mIfaceName);
             }
         }
     }
 
     public boolean isAvailable() {
-        synchronized (mMutex) {
-            return mAvailable;
-        }
-    }
-
-    private void setAvailable(boolean available) {
-        synchronized (mMutex) {
-            mAvailable = available;
-        }
+        return getCurrentState() == mInitialState;
     }
 
     public boolean isTethered() {
-        synchronized (mMutex) {
-            return mTethered;
-        }
-    }
-
-    private void setTethered(boolean tethered) {
-        synchronized (mMutex) {
-            mTethered = tethered;
-        }
+        return getCurrentState() == mTetheredState;
     }
 
     public boolean isErrored() {
-        synchronized (mMutex) {
-            return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
-        }
+        return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
     }
 
     // configured when we start tethering and unconfig'd on error or conclusion
@@ -212,8 +186,6 @@
     class InitialState extends State {
         @Override
         public void enter() {
-            setAvailable(true);
-            setTethered(false);
             mTetherController.sendTetherStateChangedBroadcast();
         }
 
@@ -241,7 +213,6 @@
     class TetheredState extends State {
         @Override
         public void enter() {
-            setAvailable(false);
             if (mUsb) {
                 if (!configureUsbIface(true, mIfaceName)) {
                     mTetherController.notifyInterfaceTetheringReadiness(false, TetherInterfaceStateMachine.this);
@@ -267,7 +238,6 @@
                 return;
             }
             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
-            setTethered(true);
             mTetherController.sendTetherStateChangedBroadcast();
         }
 
@@ -392,9 +362,7 @@
     class UnavailableState extends State {
         @Override
         public void enter() {
-            setAvailable(false);
             setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
-            setTethered(false);
             mTetherController.sendTetherStateChangedBroadcast();
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 00d7a7b..7b573da 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -384,7 +384,7 @@
             noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
             quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
             finalImportance = new ImportanceHistogram(context, "note_importance_");
-            enqueueRate = new RateEstimator(mCreated);
+            enqueueRate = new RateEstimator();
         }
 
         public AggregatedStats getPrevious() {
diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/services/core/java/com/android/server/notification/RateEstimator.java
index 4dc30a4..c17db4a 100644
--- a/services/core/java/com/android/server/notification/RateEstimator.java
+++ b/services/core/java/com/android/server/notification/RateEstimator.java
@@ -25,30 +25,43 @@
 public class RateEstimator {
     private static final double RATE_ALPHA = 0.8;
     private static final double MINIMUM_DT = 0.0005;
-    private long mLastEventTime;
-    private float mInterarrivalTime;
+    private Long mLastEventTime;
+    private Float mInterarrivalTime;
 
-    public RateEstimator(long now) {
-        mLastEventTime = now;
-    }
+    public RateEstimator() {}
 
-    /** Update the estimate to account for an event that jsut happened. */
+    /** Update the estimate to account for an event that just happened. */
     public float update(long now) {
-        mInterarrivalTime = (float) getInterarrivalEstimate(now);
+        float rate;
+        if (mLastEventTime == null) {
+            // No last event time, rate is zero.
+            rate = 0f;
+        } else {
+            // Calculate the new inter-arrival time based on last event time.
+            mInterarrivalTime = (float) getInterarrivalEstimate(now);
+            rate = (float) (1.0 / mInterarrivalTime);
+        }
         mLastEventTime = now;
-        return (float) (1.0 / mInterarrivalTime);
+        return rate;
     }
 
     /** @return the estimated rate if there were a new event right now. */
     public float getRate(long now) {
+        if (mLastEventTime == null) {
+            return 0f;
+        }
         return (float) (1.0 / getInterarrivalEstimate(now));
     }
 
     /** @return the average inter-arrival time if there were a new event right now. */
     private double getInterarrivalEstimate(long now) {
-        // a*iat_old + (1-a)*(t_now-t_last)
         double dt = ((double) (now - mLastEventTime)) / 1000.0;
         dt = Math.max(dt, MINIMUM_DT);
+        if (mInterarrivalTime == null) {
+            // No last inter-arrival time, return the new value directly.
+            return dt;
+        }
+        // a*iat_old + (1-a)*(t_now-t_last)
         return (RATE_ALPHA * mInterarrivalTime + (1.0 - RATE_ALPHA) * dt);
     }
 }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c1868a4..95550aa 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -159,6 +159,7 @@
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             mTrustAgentsCanRun = true;
             refreshAgentList(UserHandle.USER_ALL);
+            refreshDeviceLockedForUser(UserHandle.USER_ALL);
         } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
             maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_SYSTEM);
         }
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index f7cc1da..fb5a1cf 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -48,11 +48,10 @@
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
 
     private final TestLooper mLooper = new TestLooper();
-    private final Object mMutex = new Object();
     private TetherInterfaceStateMachine mTestedSm;
 
     private void initStateMachine(boolean isUsb) {
-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), isUsb, mMutex,
+        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), isUsb,
                 mNMService, mStatsService, mTetherHelper);
         mTestedSm.start();
         // Starting the state machine always puts us in a consistent state and notifies
@@ -77,7 +76,7 @@
 
     @Test
     public void startsOutAvailable() {
-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), false, mMutex,
+        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), false,
                 mNMService, mStatsService, mTetherHelper);
         mTestedSm.start();
         mLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
index cc0920f..b5698d5 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -26,18 +26,18 @@
     @Override
     public void setUp() {
         mTestStartTime = 1225731600000L;
-        mEstimator = new RateEstimator(mTestStartTime);
+        mEstimator = new RateEstimator();
     }
 
     @SmallTest
     public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception {
-        final float rate = mEstimator.update(mTestStartTime - 1000L);
-        assertFalse(Float.isInfinite(rate));
-        assertFalse(Float.isNaN(rate));
+        assertUpdateTime(mTestStartTime);
+        assertUpdateTime(mTestStartTime - 1000L);
     }
 
     @SmallTest
     public void testRunningTimeBackwardDoesntExplodeGet() throws Exception {
+        assertUpdateTime(mTestStartTime);
         final float rate = mEstimator.getRate(mTestStartTime - 1000L);
         assertFalse(Float.isInfinite(rate));
         assertFalse(Float.isNaN(rate));
@@ -45,13 +45,14 @@
 
     @SmallTest
     public void testInstantaneousEventsDontExplodeUpdate() throws Exception {
-        final float rate = mEstimator.update(mTestStartTime);
-        assertFalse(Float.isInfinite(rate));
-        assertFalse(Float.isNaN(rate));
+        assertUpdateTime(mTestStartTime);
+        assertUpdateTime(mTestStartTime);
     }
 
     @SmallTest
     public void testInstantaneousEventsDontExplodeGet() throws Exception {
+        assertUpdateTime(mTestStartTime);
+        assertUpdateTime(mTestStartTime);
         final float rate = mEstimator.getRate(mTestStartTime);
         assertFalse(Float.isInfinite(rate));
         assertFalse(Float.isNaN(rate));
@@ -59,6 +60,7 @@
 
     @SmallTest
     public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
+        assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
         long nextEventTime = postEvents(eventStart, 1, 5); // five events at 1000Hz
         final float rate = mEstimator.getRate(nextEventTime);
@@ -67,6 +69,7 @@
 
     @SmallTest
     public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception {
+        assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
         long nextEventTime = postEvents(eventStart, 1, 100); // one hundred events at 1000Hz
         final float rate = mEstimator.getRate(nextEventTime);
@@ -75,6 +78,7 @@
 
     @SmallTest
     public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception {
+        assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
         long nextEventTime = postEvents(eventStart, 10, 100); // one hundred events at 100Hz
         final float rate = mEstimator.getRate(nextEventTime);
@@ -84,6 +88,7 @@
 
     @SmallTest
     public void testRecoverQuicklyAfterSustainedBurst() throws Exception {
+        assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
         long nextEventTime = postEvents(eventStart, 10, 1000); // one hundred events at 100Hz
         final float rate = mEstimator.getRate(nextEventTime + 5000L); // two seconds later
@@ -92,12 +97,19 @@
 
     @SmallTest
     public void testEstimateShouldNotOvershoot() throws Exception {
+        assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
         long nextEventTime = postEvents(eventStart, 1, 1000); // one thousand events at 1000Hz
         final float rate = mEstimator.getRate(nextEventTime);
         assertLessThan("Rate", rate, 1000f);
     }
 
+    @SmallTest
+    public void testGetRateWithoutUpdate() throws Exception {
+        final float rate = mEstimator.getRate(mTestStartTime);
+        assertLessThan("Rate", rate, 0.1f);
+    }
+
     private void assertLessThan(String label, float a, float b)  {
         assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a < b);
     }
@@ -115,4 +127,10 @@
         }
         return time;
     }
+
+    private void assertUpdateTime(long time) {
+        final float rate = mEstimator.update(time);
+        assertFalse(Float.isInfinite(rate));
+        assertFalse(Float.isNaN(rate));
+    }
 }