Merge "Off-load unlocking users onto a worker thread" into nyc-mr1-dev
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 27b0a8b..5099eeb 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -30,7 +30,6 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-
 import java.util.List;
 
 /**
@@ -123,22 +122,36 @@
             "android.intent.action.VOICEMAIL_SMS_RECEIVED";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * event type of the SMS. Common values are "SYNC" or "STATUS"
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
+     * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
+     * it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
             "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * fields sent by the SMS
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
             "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
 
     /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+     * message body of the SMS. This extra is included if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
+     */
+    /**
+     * @hide
+     */
+    public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
+        "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
+
+    /**
      * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
      * subscription ID of the phone account that received the SMS.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 2dfa8cd..44f6fac 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
 import android.os.Handler;
@@ -91,6 +92,9 @@
     /** @hide */
     public static final int AUTOCLICK_DELAY_DEFAULT = 600;
 
+    /** @hide */
+    public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20;
+
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
@@ -99,6 +103,8 @@
 
     private IAccessibilityManager mService;
 
+    private EventDispatchThread mEventDispatchThread;
+
     final int mUserId;
 
     final Handler mHandler;
@@ -170,7 +176,7 @@
     private final IAccessibilityManagerClient.Stub mClient =
             new IAccessibilityManagerClient.Stub() {
         public void setState(int state) {
-            // We do not want to change this immediately as the applicatoin may
+            // We do not want to change this immediately as the application may
             // have already checked that accessibility is on and fired an event,
             // that is now propagating up the view tree, Hence, if accessibility
             // is now off an exception will be thrown. We want to have the exception
@@ -297,47 +303,32 @@
      * their descendants.
      */
     public void sendAccessibilityEvent(AccessibilityEvent event) {
-        final IAccessibilityManager service;
-        final int userId;
-        synchronized (mLock) {
-            service = getServiceLocked();
-            if (service == null) {
+        if (!isEnabled()) {
+            Looper myLooper = Looper.myLooper();
+            if (myLooper == Looper.getMainLooper()) {
+                throw new IllegalStateException(
+                        "Accessibility off. Did you forget to check that?");
+            } else {
+                // If we're not running on the thread with the main looper, it's possible for
+                // the state of accessibility to change between checking isEnabled and
+                // calling this method. So just log the error rather than throwing the
+                // exception.
+                Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
                 return;
             }
-            if (!mIsEnabled) {
-                Looper myLooper = Looper.myLooper();
-                if (myLooper == Looper.getMainLooper()) {
-                    throw new IllegalStateException(
-                            "Accessibility off. Did you forget to check that?");
-                } else {
-                    // If we're not running on the thread with the main looper, it's possible for
-                    // the state of accessibility to change between checking isEnabled and
-                    // calling this method. So just log the error rather than throwing the
-                    // exception.
-                    Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
-                    return;
-                }
-            }
-            userId = mUserId;
         }
-        boolean doRecycle = false;
-        try {
-            event.setEventTime(SystemClock.uptimeMillis());
-            // it is possible that this manager is in the same process as the service but
-            // client using it is called through Binder from another process. Example: MMS
-            // app adds a SMS notification and the NotificationManagerService calls this method
-            long identityToken = Binder.clearCallingIdentity();
-            doRecycle = service.sendAccessibilityEvent(event, userId);
-            Binder.restoreCallingIdentity(identityToken);
-            if (DEBUG) {
-                Log.i(LOG_TAG, event + " sent");
+        event.setEventTime(SystemClock.uptimeMillis());
+
+        getEventDispatchThread().scheduleEvent(event);
+    }
+
+    private EventDispatchThread getEventDispatchThread() {
+        synchronized (mLock) {
+            if (mEventDispatchThread == null) {
+                mEventDispatchThread = new EventDispatchThread(mService, mUserId);
+                mEventDispatchThread.start();
             }
-        } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error during sending " + event + " ", re);
-        } finally {
-            if (doRecycle) {
-                event.recycle();
-            }
+            return mEventDispatchThread;
         }
     }
 
@@ -620,7 +611,7 @@
         }
     }
 
-    private  IAccessibilityManager getServiceLocked() {
+    private IAccessibilityManager getServiceLocked() {
         if (mService == null) {
             tryConnectToServiceLocked(null);
         }
@@ -722,4 +713,99 @@
             }
         }
     }
+
+    private static class EventDispatchThread extends Thread {
+        // Second lock used to keep UI thread performant. Never try to grab mLock when holding
+        // this one, or the UI thread will block in send AccessibilityEvent.
+        private final Object mEventQueueLock = new Object();
+
+        // Two lists to hold events. The app thread fills one while we empty the other.
+        private final ArrayList<AccessibilityEvent> mEventLists0 =
+                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+        private final ArrayList<AccessibilityEvent> mEventLists1 =
+                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+
+        private boolean mPingPongListToggle;
+
+        private final IAccessibilityManager mService;
+
+        private final int mUserId;
+
+        EventDispatchThread(IAccessibilityManager service, int userId) {
+            mService = service;
+            mUserId = userId;
+        }
+
+        @Override
+        public void run() {
+            while (true) {
+                ArrayList<AccessibilityEvent> listBeingDrained;
+                synchronized (mEventQueueLock) {
+                    ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked();
+                    if (listBeingFilled.isEmpty()) {
+                        try {
+                            mEventQueueLock.wait();
+                        } catch (InterruptedException e) {
+                            // Treat as a notify
+                        }
+                    }
+                    // Swap buffers
+                    mPingPongListToggle = !mPingPongListToggle;
+                    listBeingDrained = listBeingFilled;
+                }
+                dispatchEvents(listBeingDrained);
+            }
+        }
+
+        public void scheduleEvent(AccessibilityEvent event) {
+            synchronized (mEventQueueLock) {
+                getListBeingFilledLocked().add(event);
+                mEventQueueLock.notifyAll();
+            }
+        }
+
+        private ArrayList<AccessibilityEvent> getListBeingFilledLocked() {
+            return (mPingPongListToggle) ? mEventLists0 : mEventLists1;
+        }
+
+        private void dispatchEvents(ArrayList<AccessibilityEvent> events) {
+            int eventListCapacityLowerBound = events.size();
+            while (events.size() > 0) {
+                // We don't want to consume extra memory if an app sends a lot of events in a
+                // one-off event. Cap the list length at double the max events per call.
+                // We'll end up with extra GC for apps that send huge numbers of events, but
+                // sending that many events will lead to bad performance in any case.
+                if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)
+                        && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) {
+                    events.trimToSize();
+                    eventListCapacityLowerBound = events.size();
+                }
+                // We only expect this loop to run once, as the app shouldn't be sending
+                // huge numbers of events.
+                // The clear in the called method will remove the sent events
+                dispatchOneBatchOfEvents(events.subList(0,
+                        Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL)));
+            }
+        }
+
+        private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) {
+            if (events.isEmpty()) {
+                return;
+            }
+            long identityToken = Binder.clearCallingIdentity();
+            try {
+                mService.sendAccessibilityEvents(new ParceledListSlice<>(events),
+                        mUserId);
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending multiple events");
+            }
+            Binder.restoreCallingIdentity(identityToken);
+            if (DEBUG) {
+                Log.i(LOG_TAG, events.size() + " events sent");
+            }
+            for (int i = events.size() - 1; i >= 0; i--) {
+                events.remove(i).recycle();
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 7f44bac..aa9cb39 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -21,6 +21,7 @@
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
+import android.content.pm.ParceledListSlice;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -37,7 +38,9 @@
 
     int addClient(IAccessibilityManagerClient client, int userId);
 
-    boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+    void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+
+    void sendAccessibilityEvents(in ParceledListSlice events, int userId);
 
     List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index d2d39cd..0468b64 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -52,11 +52,9 @@
 } gRectClassInfo;
 
 // Also used in PdfRenderer.cpp
-Mutex sPdfiumLock;
 int sUnmatchedPdfiumInitRequestCount = 0;
 
 static void initializeLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     if (sUnmatchedPdfiumInitRequestCount == 0) {
         FPDF_InitLibrary();
     }
@@ -64,7 +62,6 @@
 }
 
 static void destroyLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     sUnmatchedPdfiumInitRequestCount--;
     if (sUnmatchedPdfiumInitRequestCount == 0) {
        FPDF_DestroyLibrary();
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 71bec78..43550ac 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -44,11 +44,9 @@
 } gPointClassInfo;
 
 // See PdfEditor.cpp
-extern Mutex sPdfiumLock;
 extern int sUnmatchedPdfiumInitRequestCount;
 
 static void initializeLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     if (sUnmatchedPdfiumInitRequestCount == 0) {
         FPDF_InitLibrary();
     }
@@ -56,7 +54,6 @@
 }
 
 static void destroyLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     sUnmatchedPdfiumInitRequestCount--;
     if (sUnmatchedPdfiumInitRequestCount == 0) {
        FPDF_DestroyLibrary();
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e21925b..82c9300 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2519,4 +2519,13 @@
          Note: Also update appropriate overlay files. -->
     <string-array translatable="false" name="config_defaultFirstUserRestrictions">
     </string-array>
+
+    <!-- A array of regex to treat a SMS as VVM SMS if the message body matches.
+         Each item represents an entry, which consists of two parts:
+         a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and
+         then the regex itself. -->
+    <string-array translatable="false" name="config_vvmSmsFilterRegexes">
+        <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
+        <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c9ed497..b31605d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2266,6 +2266,8 @@
   <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
   <java-symbol type="id" name="profile_button" />
 
+  <java-symbol type="array" name="config_vvmSmsFilterRegexes" />
+
   <!-- Cascading submenus -->
   <java-symbol type="dimen" name="cascading_menus_min_smallest_width" />
 
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 2b70b6a..cd1f8de 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -79,8 +79,12 @@
         }
 
         mInput = input;
-        mNativeDocument = nativeOpen(mInput.getFd(), size);
-        mPageCount = nativeGetPageCount(mNativeDocument);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            mNativeDocument = nativeOpen(mInput.getFd(), size);
+            mPageCount = nativeGetPageCount(mNativeDocument);
+        }
+
         mCloseGuard.open("close");
     }
 
@@ -102,7 +106,10 @@
     public void removePage(int pageIndex) {
         throwIfClosed();
         throwIfPageNotInDocument(pageIndex);
-        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+        }
     }
 
     /**
@@ -125,11 +132,16 @@
         if (clip == null) {
             Point size = new Point();
             getPageSize(pageIndex, size);
-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
-                    0, 0, size.x, size.y);
+
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                        0, 0, size.x, size.y);
+            }
         } else {
-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
-                    clip.left, clip.top, clip.right, clip.bottom);
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                        clip.left, clip.top, clip.right, clip.bottom);
+            }
         }
     }
 
@@ -143,7 +155,10 @@
         throwIfClosed();
         throwIfOutSizeNull(outSize);
         throwIfPageNotInDocument(pageIndex);
-        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+        }
     }
 
     /**
@@ -156,7 +171,10 @@
         throwIfClosed();
         throwIfOutMediaBoxNull(outMediaBox);
         throwIfPageNotInDocument(pageIndex);
-        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+        }
     }
 
     /**
@@ -169,7 +187,10 @@
         throwIfClosed();
         throwIfMediaBoxNull(mediaBox);
         throwIfPageNotInDocument(pageIndex);
-        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+        }
     }
 
     /**
@@ -182,7 +203,10 @@
         throwIfClosed();
         throwIfOutCropBoxNull(outCropBox);
         throwIfPageNotInDocument(pageIndex);
-        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+        }
     }
 
     /**
@@ -195,7 +219,10 @@
         throwIfClosed();
         throwIfCropBoxNull(cropBox);
         throwIfPageNotInDocument(pageIndex);
-        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+        }
     }
 
     /**
@@ -205,7 +232,10 @@
      */
     public boolean shouldScaleForPrinting() {
         throwIfClosed();
-        return nativeScaleForPrinting(mNativeDocument);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeScaleForPrinting(mNativeDocument);
+        }
     }
 
     /**
@@ -219,7 +249,10 @@
     public void write(ParcelFileDescriptor output) throws IOException {
         try {
             throwIfClosed();
-            nativeWrite(mNativeDocument, output.getFd());
+
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeWrite(mNativeDocument, output.getFd());
+            }
         } finally {
             IoUtils.closeQuietly(output);
         }
@@ -247,7 +280,9 @@
     }
 
     private void doClose() {
-        nativeClose(mNativeDocument);
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeClose(mNativeDocument);
+        }
         IoUtils.closeQuietly(mInput);
         mInput = null;
         mCloseGuard.close();
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 520ebe5..cfc1309 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -99,6 +99,12 @@
  * @see #close()
  */
 public final class PdfRenderer implements AutoCloseable {
+    /**
+     * Any call the native pdfium code has to be single threaded as the library does not support
+     * parallel use.
+     */
+    final static Object sPdfiumLock = new Object();
+
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final Point mTempPoint = new Point();
@@ -154,8 +160,12 @@
         }
 
         mInput = input;
-        mNativeDocument = nativeCreate(mInput.getFd(), size);
-        mPageCount = nativeGetPageCount(mNativeDocument);
+
+        synchronized (sPdfiumLock) {
+            mNativeDocument = nativeCreate(mInput.getFd(), size);
+            mPageCount = nativeGetPageCount(mNativeDocument);
+        }
+
         mCloseGuard.open("close");
     }
 
@@ -189,7 +199,10 @@
      */
     public boolean shouldScaleForPrinting() {
         throwIfClosed();
-        return nativeScaleForPrinting(mNativeDocument);
+
+        synchronized (sPdfiumLock) {
+            return nativeScaleForPrinting(mNativeDocument);
+        }
     }
 
     /**
@@ -224,7 +237,9 @@
         if (mCurrentPage != null) {
             mCurrentPage.close();
         }
-        nativeClose(mNativeDocument);
+        synchronized (sPdfiumLock) {
+            nativeClose(mNativeDocument);
+        }
         try {
             mInput.close();
         } catch (IOException ioe) {
@@ -277,7 +292,9 @@
 
         private Page(int index) {
             Point size = mTempPoint;
-            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            synchronized (sPdfiumLock) {
+                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            }
             mIndex = index;
             mWidth = size.x;
             mHeight = size.y;
@@ -384,8 +401,10 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
-                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
+            synchronized (sPdfiumLock) {
+                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
+                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
+            }
         }
 
         /**
@@ -412,7 +431,9 @@
         }
 
         private void doClose() {
-            nativeClosePage(mNativePage);
+            synchronized (sPdfiumLock) {
+                nativeClosePage(mNativePage);
+            }
             mNativePage = 0;
             mCloseGuard.close();
             mCurrentPage = null;
diff --git a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
index 20173b0..24cbfbd 100644
--- a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
@@ -4,7 +4,7 @@
     <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
     <string name="action_use_network" msgid="6076184727448466030">"যেভাবে আছে সেভাবেই এই নেটওয়ার্ক ব্যবহার করুন"</string>
     <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটওয়ার্ক ব্যবহার করবেন না"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন করুন"</string>
+    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন"</string>
     <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string>
     <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string>
     <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index b82f8dd..ae8938d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -401,8 +401,13 @@
                 return true;
             }
 
-            // Open the Close drawer if it is closed and we're at the top of a root.
-            if (size <= 1) {
+            final Intent intent = getIntent();
+            final boolean launchedExternally = intent != null && intent.getData() != null
+                    && mState.action == State.ACTION_BROWSE;
+
+            // Open the Close drawer if it is closed and we're at the top of a root, but only when
+            // not launched by another app.
+            if (size <= 1 && !launchedExternally) {
                 mDrawer.setOpen(true);
                 // Remember so we don't just close it again if back is pressed again.
                 mDrawerLastFiddled = System.currentTimeMillis();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index d2e9885..b3db037 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
 
@@ -85,6 +86,15 @@
     public @interface PermissionStatus {}
 
     /**
+     * Clears all preferences associated with a given package.
+     *
+     * <p>Typically called when a package is removed or when user asked to clear its data.
+     */
+    static void clearPackagePreferences(Context context, String packageName) {
+        clearScopedAccessPreferences(context, packageName);
+    }
+
+    /**
      * Methods below are used to keep track of denied user requests on scoped directory access so
      * the dialog is not offered when user checked the 'Do not ask again' box
      *
@@ -108,6 +118,23 @@
       getPrefs(context).edit().putInt(key, status).apply();
     }
 
+    private static void clearScopedAccessPreferences(Context context, String packageName) {
+        final String keySubstring = "|" + packageName + "|";
+        final SharedPreferences prefs = getPrefs(context);
+        Editor editor = null;
+        for (final String key : prefs.getAll().keySet()) {
+            if (key.contains(keySubstring)) {
+                if (editor == null) {
+                    editor = prefs.edit();
+                }
+                editor.remove(key);
+            }
+        }
+        if (editor != null) {
+            editor.apply();
+        }
+    }
+
     private static String getScopedAccessDenialsKey(String packageName, String uuid,
             String directory) {
         final int userId = UserHandle.myUserId();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
index aef63af..fd1183f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 
 /**
- * Clean up {@link RecentsProvider} when packages are removed.
+ * Cleans up {@link RecentsProvider} and {@link LocalPreferences} when packages are removed.
  */
 public class PackageReceiver extends BroadcastReceiver {
     @Override
@@ -31,15 +31,19 @@
         final ContentResolver resolver = context.getContentResolver();
 
         final String action = intent.getAction();
+        final Uri data = intent.getData();
+        final String packageName = data == null ? null : data.getSchemeSpecificPart();
+
         if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
             resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
-
+            if (packageName != null) {
+                LocalPreferences.clearPackagePreferences(context, packageName);
+            }
         } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
-            final Uri data = intent.getData();
-            if (data != null) {
-                final String packageName = data.getSchemeSpecificPart();
+            if (packageName != null) {
                 resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
                         packageName, null);
+                LocalPreferences.clearPackagePreferences(context, packageName);
             }
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 1118171..1de3bbc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -117,7 +117,9 @@
         byteCopyDocument(src, dest);
 
         // Remove the source document.
-        deleteDocument(src, srcParent);
+        if(!isCanceled()) {
+            deleteDocument(src, srcParent);
+        }
     }
 
     @Override
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 78b9927..7fe0d2f 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -566,6 +566,7 @@
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
 
+        query = query.toLowerCase();
         final File parent;
         synchronized (mRootsLock) {
             parent = mRoots.get(rootId).path;
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 3debf8e..d4e7963 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -60,7 +60,7 @@
       <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
+    <string name="printer_info_desc" msgid="7181988788991581654">"此打印机的详细信息"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"无法创建文件"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA-land/strings.xml b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
index bdc652a..56a4ad2 100644
--- a/packages/SystemUI/res/values-bs-rBA-land/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u pejzažnom prikazu."</string>
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u vodoravnom prikazu."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings_car.xml b/packages/SystemUI/res/values-it/strings_car.xml
index ae26c9e..19c4e2b 100644
--- a/packages/SystemUI/res/values-it/strings_car.xml
+++ b/packages/SystemUI/res/values-it/strings_car.xml
@@ -20,5 +20,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Guida in modo sicuro"</string>
-    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente coscienti delle condizioni di guida e rispettare le leggi vigenti. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, non adatte, vietate o implicare l\'attraversamento di confini. Anche le informazioni sulle attività commerciali potrebbero essere imprecise o incomplete. I dati non vengono forniti in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare il dispositivo mobile e non utilizzare app non progettate per Android Auto durante la guida."</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente informati sulle condizioni della strada e rispettare la legislazione vigente. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, inadatte, vietate o richiedere l\'attraversamento di aree amministrative. Anche le informazioni sugli esercizi commerciali potrebbero essere imprecise o incomplete. I dati forniti non sono aggiornati in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare dispositivi mobili e app non destinate ad Android Auto durante la guida."</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
index bad739fd..4585fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -62,36 +62,36 @@
     @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         Data data = mStrokeMap.get(stroke);
-        return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
-                + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
+        return 2 * SpeedRatioEvaluator.evaluate(data.maxSpeedRatio);
     }
 
     private static class Data {
-        public Point previousPoint;
-        public float previousSpeed;
-        public float previousDistance;
-        public float maxSpeedRatio;
-        public float maxDistanceRatio;
+
+        static final float MILLIS_TO_NANOS = 1e6f;
+
+        Point previousPoint;
+        float previousSpeed = 0;
+        float maxSpeedRatio = 0;
 
         public Data(Point point) {
             previousPoint = point;
-            previousSpeed = previousDistance = 0.0f;
-            maxDistanceRatio = maxSpeedRatio = 0.0f;
         }
 
         public void addPoint(Point point) {
             float distance = previousPoint.dist(point);
             float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
             float speed = distance / duration;
-            if (previousDistance != 0.0f) {
-                maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
-            }
 
+            if (duration > 20 * MILLIS_TO_NANOS || duration < 5 * MILLIS_TO_NANOS) {
+                // reject this segment and ensure we won't use data about it in the next round.
+                previousSpeed = 0;
+                previousPoint = point;
+                return;
+            }
             if (previousSpeed != 0.0f) {
                 maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
             }
 
-            previousDistance = distance;
             previousSpeed = speed;
             previousPoint = point;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
deleted file mode 100644
index 8acb009..0000000
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.systemui.classifier;
-
-public class DistanceRatioEvaluator {
-    public static float evaluate(float value) {
-        float evaluation = 0.0f;
-        if (value <= 1.0) evaluation++;
-        if (value <= 0.5) evaluation++;
-        if (value > 4.0) evaluation++;
-        if (value > 7.0) evaluation++;
-        if (value > 14.0) evaluation++;
-        return evaluation;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
index 4c6cea0..e34f222 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
@@ -19,6 +19,7 @@
 public class SpeedRatioEvaluator {
     public static float evaluate(float value) {
         float evaluation = 0.0f;
+        if (value == 0) return 0;
         if (value <= 1.0) evaluation++;
         if (value <= 0.5) evaluation++;
         if (value > 9.0) evaluation++;
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index 4865e96..e2e1e44 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -25,5 +25,5 @@
     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"Trimise:"</string>
     <string name="data_received" msgid="4062776929376067820">"Primite:"</string>
-    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
+    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g>   octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g>   pachete"</string>
 </resources>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 695ea60..b1fbcde 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -451,7 +451,7 @@
     }
 
     @Override
-    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
+    public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -459,23 +459,39 @@
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
-            if (resolvedUserId != mCurrentUserId) {
-                return true; // yes, recycle the event
+            if (resolvedUserId == mCurrentUserId) {
+                if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
+                    mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(
+                            event.getWindowId(), event.getSourceNodeId(),
+                            event.getEventType(), event.getAction());
+                    mSecurityPolicy.updateEventSourceLocked(event);
+                    notifyAccessibilityServicesDelayedLocked(event, false);
+                    notifyAccessibilityServicesDelayedLocked(event, true);
+                }
+                if (mHasInputFilter && mInputFilter != null) {
+                    mMainHandler.obtainMessage(
+                            MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
+                            AccessibilityEvent.obtain(event)).sendToTarget();
+                }
             }
-            if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
-                mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
-                        event.getSourceNodeId(), event.getEventType(), event.getAction());
-                mSecurityPolicy.updateEventSourceLocked(event);
-                notifyAccessibilityServicesDelayedLocked(event, false);
-                notifyAccessibilityServicesDelayedLocked(event, true);
-            }
-            if (mHasInputFilter && mInputFilter != null) {
-                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
-                        AccessibilityEvent.obtain(event)).sendToTarget();
-            }
+        }
+        if (OWN_PROCESS_ID != Binder.getCallingPid()) {
             event.recycle();
         }
-        return (OWN_PROCESS_ID != Binder.getCallingPid());
+    }
+
+    @Override
+    public void sendAccessibilityEvents(ParceledListSlice events, int userId) {
+        List<AccessibilityEvent> a11yEvents = events.getList();
+        // Grab the lock once for the entire batch
+        synchronized (mLock) {
+            int numEventsToProcess = Math.min(a11yEvents.size(),
+                    AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+            for (int i = 0; i < numEventsToProcess; i++) {
+                AccessibilityEvent event = a11yEvents.get(i);
+                sendAccessibilityEvent(event, userId);
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index da615ec..f3fc676 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -133,7 +133,6 @@
 import android.os.HandlerThread;
 import android.os.IDeviceIdleController;
 import android.os.INetworkManagementService;
-import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
 import android.os.PowerManager;
@@ -286,7 +285,6 @@
     private static final int MSG_LIMIT_REACHED = 5;
     private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
     private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
-    private static final int MSG_SCREEN_ON_CHANGED = 8;
     private static final int MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED = 9;
     private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
     private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
@@ -294,7 +292,6 @@
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
-    private final IPowerManager mPowerManager;
     private final INetworkStatsService mNetworkStats;
     private final INetworkManagementService mNetworkManager;
     private UsageStatsManagerInternal mUsageStats;
@@ -312,7 +309,6 @@
 
     @GuardedBy("allLocks") volatile boolean mSystemReady;
 
-    @GuardedBy("mUidRulesFirstLock") volatile boolean mScreenOn;
     @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
     @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower;
     @GuardedBy("mUidRulesFirstLock") volatile boolean mDeviceIdleMode;
@@ -418,9 +414,8 @@
     // TODO: migrate notifications to SystemUI
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
-            IPowerManager powerManager, INetworkStatsService networkStats,
-            INetworkManagementService networkManagement) {
-        this(context, activityManager, powerManager, networkStats, networkManagement,
+            INetworkStatsService networkStats, INetworkManagementService networkManagement) {
+        this(context, activityManager, networkStats, networkManagement,
                 NtpTrustedTime.getInstance(context), getSystemDir(), false);
     }
 
@@ -429,12 +424,10 @@
     }
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
-            IPowerManager powerManager, INetworkStatsService networkStats,
-            INetworkManagementService networkManagement, TrustedTime time, File systemDir,
-            boolean suppressDefaultPolicy) {
+            INetworkStatsService networkStats, INetworkManagementService networkManagement,
+            TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
-        mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
@@ -618,8 +611,6 @@
             }
         }
 
-        updateScreenOn();
-
         try {
             mActivityManager.registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
@@ -628,14 +619,6 @@
             // ignored; both services live in system_server
         }
 
-        // TODO: traverse existing processes to know foreground state, or have
-        // activitymanager dispatch current state when new observer attached.
-
-        final IntentFilter screenFilter = new IntentFilter();
-        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
-        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        mContext.registerReceiver(mScreenReceiver, screenFilter);
-
         // listen for changes to power save whitelist
         final IntentFilter whitelistFilter = new IntentFilter(
                 PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
@@ -734,15 +717,6 @@
         }
     };
 
-    final private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // screen-related broadcasts are protected by system, no need
-            // for permissions check.
-            mHandler.obtainMessage(MSG_SCREEN_ON_CHANGED).sendToTarget();
-        }
-    };
-
     final private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -2520,7 +2494,7 @@
 
     private boolean isUidStateForegroundUL(int state) {
         // only really in foreground when screen is also on
-        return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
+        return state <= ActivityManager.PROCESS_STATE_TOP;
     }
 
     /**
@@ -2591,31 +2565,6 @@
         }
     }
 
-    private void updateScreenOn() {
-        synchronized (mUidRulesFirstLock) {
-            try {
-                mScreenOn = mPowerManager.isInteractive();
-            } catch (RemoteException e) {
-                // ignored; service lives in system_server
-            }
-            updateRulesForScreenUL();
-        }
-    }
-
-    /**
-     * Update rules that might be changed by {@link #mScreenOn} value.
-     */
-    private void updateRulesForScreenUL() {
-        // only update rules for anyone with foreground activities
-        final int size = mUidState.size();
-        for (int i = 0; i < size; i++) {
-            if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-                final int uid = mUidState.keyAt(i);
-                updateRestrictionRulesForUidUL(uid);
-            }
-        }
-    }
-
     static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
         return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
     }
@@ -2997,12 +2946,8 @@
             mUidRules.put(uid, newUidRules);
         }
 
-        boolean changed = false;
-
         // Second step: apply bw changes based on change of state.
         if (newRule != oldRule) {
-            changed = true;
-
             if ((newRule & RULE_TEMPORARY_ALLOW_METERED) != 0) {
                 // Temporarily whitelist foreground app, removing from blacklist if necessary
                 // (since bw_penalty_box prevails over bw_happy_box).
@@ -3082,7 +3027,6 @@
 
         final boolean isIdle = isUidIdle(uid);
         final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
-        final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final int oldUidRules = mUidRules.get(uid, RULE_NONE);
         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
 
@@ -3105,7 +3049,7 @@
         final int newUidRules = (oldUidRules & MASK_METERED_NETWORKS) | newRule;
 
         if (LOGV) {
-            Log.v(TAG, "updateRulesForNonMeteredNetworksUL(" + uid + ")"
+            Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
                     + ", isIdle: " + isIdle
                     + ", mRestrictPower: " + mRestrictPower
                     + ", mDeviceIdleMode: " + mDeviceIdleMode
@@ -3347,10 +3291,6 @@
                     }
                     return true;
                 }
-                case MSG_SCREEN_ON_CHANGED: {
-                    updateScreenOn();
-                    return true;
-                }
                 case MSG_UPDATE_INTERFACE_QUOTA: {
                     removeInterfaceQuota((String) msg.obj);
                     // int params need to be stitched back into a long
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a839373..97a829e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -809,10 +809,8 @@
 
                 traceBeginAndSlog("StartNetworkPolicyManagerService");
                 try {
-                    networkPolicy = new NetworkPolicyManagerService(
-                            context, mActivityManagerService,
-                            (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
-                            networkStats, networkManagement);
+                    networkPolicy = new NetworkPolicyManagerService(context,
+                            mActivityManagerService, networkStats, networkManagement);
                     ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkPolicy Service", e);
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 654ef18..6d90203 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -382,6 +382,7 @@
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
     private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
 
     private final String mTag;
     private final Context mContext;
@@ -476,6 +477,7 @@
         // Super simple StateMachine.
         addState(mStoppedState);
         addState(mStartedState);
+            addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
@@ -570,7 +572,7 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.println("StateMachine dump:");
+        pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
@@ -768,6 +770,11 @@
         //         - IPv6 addresses
         //         - IPv6 routes
         //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpManager its own netlink socket(s)
+        // so as to track all required information directly.
         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
@@ -939,16 +946,30 @@
         return true;
     }
 
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        try {
+            mNwService.disableIpv6(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to disable IPv6" + e);
+        }
+
+        try {
+            mNwService.clearInterfaceAddresses(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to clear addresses " + e);
+        }
+    }
+
 
     class StoppedState extends State {
         @Override
         public void enter() {
-            try {
-                mNwService.disableIpv6(mInterfaceName);
-                mNwService.clearInterfaceAddresses(mInterfaceName);
-            } catch (Exception e) {
-                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
-            }
+            stopAllIP();
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
@@ -1023,12 +1044,71 @@
     }
 
     class StartedState extends State {
-        private boolean mDhcpActionInFlight;
-
         @Override
         public void enter() {
             mStartTimeMillis = SystemClock.elapsedRealtime();
 
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                transitionTo(mRunningState);
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpManager restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+            return HANDLED;
+        }
+
+        boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() &&
+                    !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                     mCallback, mMulticastFiltering);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
@@ -1037,12 +1117,6 @@
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
             if (mConfiguration.mEnableIPv6) {
                 // TODO: Consider transitionTo(mStoppingState) if this fails.
                 startIPv6();
@@ -1070,7 +1144,6 @@
 
         @Override
         public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
             stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
@@ -1167,10 +1240,6 @@
                     break;
                 }
 
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index 026a2ad..6e3e6c6 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -131,18 +131,10 @@
     public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
 
-        when(mMockService.sendAccessibilityEvent(eq(sentEvent), anyInt()))
-                .thenReturn(true  /* should recycle event object */)
-                .thenReturn(false /* should not recycle event object */);
-
         AccessibilityManager manager = createManager(true);
         manager.sendAccessibilityEvent(sentEvent);
 
         assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
-
-        manager.sendAccessibilityEvent(sentEvent);
-
-        assertNotSame("The event should not be recycled.", sentEvent, AccessibilityEvent.obtain());
     }
 
     @MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 979f160..541be3d 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -69,7 +69,6 @@
 import android.net.NetworkTemplate;
 import android.os.Binder;
 import android.os.INetworkManagementService;
-import android.os.IPowerManager;
 import android.os.MessageQueue.IdleHandler;
 import android.os.UserHandle;
 import android.test.AndroidTestCase;
@@ -115,7 +114,6 @@
     private File mPolicyDir;
 
     private IActivityManager mActivityManager;
-    private IPowerManager mPowerManager;
     private INetworkStatsService mStatsService;
     private INetworkManagementService mNetworkManager;
     private INetworkPolicyListener mPolicyListener;
@@ -187,7 +185,6 @@
         }
 
         mActivityManager = createMock(IActivityManager.class);
-        mPowerManager = createMock(IPowerManager.class);
         mStatsService = createMock(INetworkStatsService.class);
         mNetworkManager = createMock(INetworkManagementService.class);
         mPolicyListener = createMock(INetworkPolicyListener.class);
@@ -195,7 +192,7 @@
         mConnManager = createMock(IConnectivityManager.class);
         mNotifManager = createMock(INotificationManager.class);
 
-        mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mPowerManager,
+        mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
                 mStatsService, mNetworkManager, mTime, mPolicyDir, true);
         mService.bindConnectivityManager(mConnManager);
         mService.bindNotificationManager(mNotifManager);
@@ -217,8 +214,6 @@
         mNetworkManager.registerObserver(capture(networkObserver));
         expectLastCall().atLeastOnce();
 
-        // expect to answer screen status during systemReady()
-        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
         expectCurrentTime();
 
@@ -240,7 +235,6 @@
         mPolicyDir = null;
 
         mActivityManager = null;
-        mPowerManager = null;
         mStatsService = null;
         mPolicyListener = null;
         mTime = null;
@@ -313,48 +307,6 @@
     }
 
     @Suppress
-    public void testScreenChangesRules() throws Exception {
-        Future<Void> future;
-
-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
-        expectSetUidForeground(UID_A, true);
-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
-        replay();
-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
-        future.get();
-        verifyAndReset();
-
-        // push strict policy for foreground uid, verify ALLOW rule
-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
-        expectSetUidForeground(UID_A, true);
-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
-        replay();
-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
-        future.get();
-        verifyAndReset();
-
-        // now turn screen off and verify REJECT rule
-        expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
-        expectSetUidMeteredNetworkBlacklist(UID_A, true);
-        expectSetUidForeground(UID_A, false);
-        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
-        replay();
-        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
-        future.get();
-        verifyAndReset();
-
-        // and turn screen back on, verify ALLOW rule restored
-        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
-        expectSetUidForeground(UID_A, true);
-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
-        replay();
-        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
-        future.get();
-        verifyAndReset();
-    }
-
-    @Suppress
     public void testPolicyNone() throws Exception {
         Future<Void> future;
 
@@ -1049,14 +1001,14 @@
     }
 
     private void replay() {
-        EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
-                mNetworkManager, mTime, mConnManager, mNotifManager);
+        EasyMock.replay(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
+                mConnManager, mNotifManager);
     }
 
     private void verifyAndReset() {
-        EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
-                mNetworkManager, mTime, mConnManager, mNotifManager);
-        EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
-                mNetworkManager, mTime, mConnManager, mNotifManager);
+        EasyMock.verify(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
+                mConnManager, mNotifManager);
+        EasyMock.reset(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
+                mConnManager, mNotifManager);
     }
 }