diff options
29 files changed, 511 insertions, 345 deletions
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index 27b0a8baf62b..5099eebf6eb1 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -30,7 +30,6 @@ import android.provider.CallLog.Calls; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.Voicemail; - import java.util.List; /** @@ -123,22 +122,36 @@ public class VoicemailContract { "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 2dfa8cdd3db9..44f6facd88f5 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -21,6 +21,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; 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 @@ public final class AccessibilityManager { /** @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 @@ public final class AccessibilityManager { private IAccessibilityManager mService; + private EventDispatchThread mEventDispatchThread; + final int mUserId; final Handler mHandler; @@ -170,7 +176,7 @@ public final class AccessibilityManager { 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 @@ public final class AccessibilityManager { * 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"); - } - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error during sending " + event + " ", re); - } finally { - if (doRecycle) { - event.recycle(); + event.setEventTime(SystemClock.uptimeMillis()); + + getEventDispatchThread().scheduleEvent(event); + } + + private EventDispatchThread getEventDispatchThread() { + synchronized (mLock) { + if (mEventDispatchThread == null) { + mEventDispatchThread = new EventDispatchThread(mService, mUserId); + mEventDispatchThread.start(); } + return mEventDispatchThread; } } @@ -620,7 +611,7 @@ public final class AccessibilityManager { } } - private IAccessibilityManager getServiceLocked() { + private IAccessibilityManager getServiceLocked() { if (mService == null) { tryConnectToServiceLocked(null); } @@ -722,4 +713,99 @@ public final class AccessibilityManager { } } } + + 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 7f44bac8bc6f..aa9cb39062f9 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -21,6 +21,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; 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 @@ interface IAccessibilityManager { 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 d2d39cd0b286..0468b644862d 100644 --- a/core/jni/android/graphics/pdf/PdfEditor.cpp +++ b/core/jni/android/graphics/pdf/PdfEditor.cpp @@ -52,11 +52,9 @@ static struct { } 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 initializeLibraryIfNeeded() { } 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 71bec7845fd7..43550ac9ed72 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -44,11 +44,9 @@ static struct { } 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 initializeLibraryIfNeeded() { } 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 e21925bb3fb6..82c9300f2fc4 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 c9ed497679d0..b31605d21ecd 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 2b70b6a45f82..cd1f8de6ee0f 100644 --- a/graphics/java/android/graphics/pdf/PdfEditor.java +++ b/graphics/java/android/graphics/pdf/PdfEditor.java @@ -79,8 +79,12 @@ public final class PdfEditor { } 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 final class PdfEditor { public void removePage(int pageIndex) { throwIfClosed(); throwIfPageNotInDocument(pageIndex); - mPageCount = nativeRemovePage(mNativeDocument, pageIndex); + + synchronized (PdfRenderer.sPdfiumLock) { + mPageCount = nativeRemovePage(mNativeDocument, pageIndex); + } } /** @@ -125,11 +132,16 @@ public final class PdfEditor { 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 @@ public final class PdfEditor { throwIfClosed(); throwIfOutSizeNull(outSize); throwIfPageNotInDocument(pageIndex); - nativeGetPageSize(mNativeDocument, pageIndex, outSize); + + synchronized (PdfRenderer.sPdfiumLock) { + nativeGetPageSize(mNativeDocument, pageIndex, outSize); + } } /** @@ -156,7 +171,10 @@ public final class PdfEditor { throwIfClosed(); throwIfOutMediaBoxNull(outMediaBox); throwIfPageNotInDocument(pageIndex); - return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox); + + synchronized (PdfRenderer.sPdfiumLock) { + return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox); + } } /** @@ -169,7 +187,10 @@ public final class PdfEditor { throwIfClosed(); throwIfMediaBoxNull(mediaBox); throwIfPageNotInDocument(pageIndex); - nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox); + + synchronized (PdfRenderer.sPdfiumLock) { + nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox); + } } /** @@ -182,7 +203,10 @@ public final class PdfEditor { throwIfClosed(); throwIfOutCropBoxNull(outCropBox); throwIfPageNotInDocument(pageIndex); - return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox); + + synchronized (PdfRenderer.sPdfiumLock) { + return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox); + } } /** @@ -195,7 +219,10 @@ public final class PdfEditor { throwIfClosed(); throwIfCropBoxNull(cropBox); throwIfPageNotInDocument(pageIndex); - nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox); + + synchronized (PdfRenderer.sPdfiumLock) { + nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox); + } } /** @@ -205,7 +232,10 @@ public final class PdfEditor { */ public boolean shouldScaleForPrinting() { throwIfClosed(); - return nativeScaleForPrinting(mNativeDocument); + + synchronized (PdfRenderer.sPdfiumLock) { + return nativeScaleForPrinting(mNativeDocument); + } } /** @@ -219,7 +249,10 @@ public final class PdfEditor { 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 @@ public final class PdfEditor { } 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 520ebe5f2db8..cfc130990e92 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -99,6 +99,12 @@ import java.lang.annotation.RetentionPolicy; * @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 @@ public final class PdfRenderer implements AutoCloseable { } 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 final class PdfRenderer implements AutoCloseable { */ public boolean shouldScaleForPrinting() { throwIfClosed(); - return nativeScaleForPrinting(mNativeDocument); + + synchronized (sPdfiumLock) { + return nativeScaleForPrinting(mNativeDocument); + } } /** @@ -224,7 +237,9 @@ public final class PdfRenderer implements AutoCloseable { if (mCurrentPage != null) { mCurrentPage.close(); } - nativeClose(mNativeDocument); + synchronized (sPdfiumLock) { + nativeClose(mNativeDocument); + } try { mInput.close(); } catch (IOException ioe) { @@ -277,7 +292,9 @@ public final class PdfRenderer implements AutoCloseable { 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 @@ public final class PdfRenderer implements AutoCloseable { 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 @@ public final class PdfRenderer implements AutoCloseable { } private void doClose() { - nativeClosePage(mNativePage); + synchronized (sPdfiumLock) { + nativeClosePage(mNativePage); + } mNativePage = 0; mCloseGuard.close(); mCurrentPage = null; diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index b82f8dd3d7a3..ae8938de1e3d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -401,8 +401,13 @@ public class FilesActivity extends BaseActivity { 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 d2e9885edf14..b3db037697f3 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.IntDef; 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 class LocalPreferences { 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 @@ public class LocalPreferences { 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 aef63afcbcd7..fd1183fda13d 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.content.Intent; 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 @@ public class PackageReceiver extends BroadcastReceiver { 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/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index b7c0a9c1be1b..8aa7f6e69458 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -53,10 +53,13 @@ import android.provider.DocumentsContract.Document; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v13.view.DragStartHelper; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager.SpanSizeLookup; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.OnItemTouchListener; +import android.support.v7.widget.RecyclerView.Recycler; import android.support.v7.widget.RecyclerView.RecyclerListener; import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.BidiFormatter; @@ -243,7 +246,40 @@ public class DirectoryFragment extends Fragment mRecView.setAdapter(mAdapter); - mLayout = new GridLayoutManager(getContext(), mColumnCount); + // Switch Access Accessibility API needs an {@link AccessibilityDelegate} to know the proper + // route when user selects an UI element. It usually guesses this if the element has an + // {@link OnClickListener}, but since we do not have one for itemView, we will need to + // manually route it to the right behavior. RecyclerView has its own AccessibilityDelegate, + // and routes it to its LayoutManager; so we must override the LayoutManager's accessibility + // methods to route clicks correctly. + mLayout = new GridLayoutManager(getContext(), mColumnCount) { + @Override + public void onInitializeAccessibilityNodeInfoForItem( + RecyclerView.Recycler recycler, RecyclerView.State state, + View host, AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info); + info.addAction(AccessibilityActionCompat.ACTION_CLICK); + } + + @Override + public boolean performAccessibilityActionForItem( + RecyclerView.Recycler recycler, RecyclerView.State state, View view, + int action, Bundle args) { + // We are only handling click events; route all other to default implementation + if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) { + RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view); + if (vh instanceof DocumentHolder) { + DocumentHolder dh = (DocumentHolder) vh; + if (dh.mEventListener != null) { + dh.mEventListener.onActivate(dh); + return true; + } + } + } + return super.performAccessibilityActionForItem(recycler, state, view, action, + args); + } + }; SpanSizeLookup lookup = mAdapter.createSpanSizeLookup(); if (lookup != null) { mLayout.setSpanSizeLookup(lookup); diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java index 111817132fa1..1de3bbc20496 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 @@ final class MoveJob extends CopyJob { 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 78b99274e444..7fe0d2fd074a 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -566,6 +566,7 @@ public class ExternalStorageProvider extends DocumentsProvider { 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 3debf8e60cdb..d4e796339bc9 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 bdc652af8f1a..56a4ad276d08 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 ae26c9e102bd..19c4e2b02ad0 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 bad739fdc764..4585fe9fb868 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 @@ public class AccelerationClassifier extends StrokeClassifier { @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 8acb009a230f..000000000000 --- 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 4c6cea0367ad..e34f222d3799 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 @@ package com.android.systemui.classifier; 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 4865e964fc74..e2e1e44021b0 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 695ea606a90b..b1fbcde6c727 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } @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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); // This method does nothing for a background user. - if (resolvedUserId != mCurrentUserId) { - return true; // yes, recycle the event - } - 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 (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 (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 da615ec21720..f3fc676fe2e6 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.Handler; 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - updateScreenOn(); - try { mActivityManager.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE); @@ -628,14 +619,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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 a839373d787e..97a829ecac46 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -809,10 +809,8 @@ public final class SystemServer { 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 654ef18f9608..6d9020390bef 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -382,6 +382,7 @@ public class IpManager extends StateMachine { 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 @@ public class IpManager extends StateMachine { // Super simple StateMachine. addState(mStoppedState); addState(mStartedState); + addState(mRunningState, mStartedState); addState(mStoppingState); setInitialState(mStoppedState); @@ -570,7 +572,7 @@ public class IpManager extends StateMachine { 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 @@ public class IpManager extends StateMachine { // - 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 @@ public class IpManager extends StateMachine { 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 @@ public class IpManager extends StateMachine { } 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 @@ public class IpManager extends StateMachine { 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 @@ public class IpManager extends StateMachine { @Override public void exit() { - mProvisioningTimeoutAlarm.cancel(); stopDhcpAction(); if (mIpReachabilityMonitor != null) { @@ -1167,10 +1240,6 @@ public class IpManager extends StateMachine { 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 026a2adc1f96..6e3e6c6278a9 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 class AccessibilityManagerTest extends AndroidTestCase { 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 979f160d3c7b..541be3dad376 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.NetworkStats; 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private File mPolicyDir; private IActivityManager mActivityManager; - private IPowerManager mPowerManager; private INetworkStatsService mStatsService; private INetworkManagementService mNetworkManager; private INetworkPolicyListener mPolicyListener; @@ -187,7 +185,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } mActivityManager = createMock(IActivityManager.class); - mPowerManager = createMock(IPowerManager.class); mStatsService = createMock(INetworkStatsService.class); mNetworkManager = createMock(INetworkManagementService.class); mPolicyListener = createMock(INetworkPolicyListener.class); @@ -195,7 +192,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mPolicyDir = null; mActivityManager = null; - mPowerManager = null; mStatsService = null; mPolicyListener = null; mTime = null; @@ -313,48 +307,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } @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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } 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); } } diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py index 2956d87f247c..336fce96650f 100755 --- a/tools/fonts/fontchain_lint.py +++ b/tools/fonts/fontchain_lint.py @@ -256,8 +256,8 @@ def parse_fonts_xml(fonts_xml_path): def check_emoji_coverage(all_emoji, equivalent_emoji): - emoji_font = get_emoji_font() - check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji) + emoji_font = get_emoji_font() + check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji) def get_emoji_font(): @@ -274,15 +274,12 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): assert sequence in coverage, ( '%s is not supported in the emoji font.' % printable(sequence)) - # disable temporarily - we cover more than this - """ for sequence in coverage: if sequence in {0x0000, 0x000D, 0x0020}: # The font needs to support a few extra characters, which is OK continue assert sequence in all_emoji, ( 'Emoji font should not support %s.' % printable(sequence)) - """ for first, second in sorted(equivalent_emoji.items()): assert coverage[first] == coverage[second], ( @@ -290,8 +287,6 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): printable(first), printable(second))) - # disable temporarily - some equivalent sequences we don't even know about - """ for glyph in set(coverage.values()): maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph] if len(maps_to_glyph) > 1: @@ -307,7 +302,7 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): 'The sequences %s should not result in the same glyph %s' % ( printable(equivalent_seqs), glyph)) - """ + def check_emoji_defaults(default_emoji): missing_text_chars = _emoji_properties['Emoji'] - default_emoji @@ -334,15 +329,9 @@ def check_emoji_defaults(default_emoji): # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and # webdings yet. missing_text_chars -= _chars_by_age['7.0'] - # TODO: Remove these after b/26113320 is fixed - missing_text_chars -= { - 0x263A, # WHITE SMILING FACE - 0x270C, # VICTORY HAND - 0x2744, # SNOWFLAKE - 0x2764, # HEAVY BLACK HEART - } assert missing_text_chars == set(), ( - 'Text style version of some emoji characters are missing: ' + repr(missing_text_chars)) + 'Text style version of some emoji characters are missing: ' + + repr(missing_text_chars)) # Setting reverse to true returns a dictionary that maps the values to sets of @@ -362,7 +351,7 @@ def parse_unicode_datafile(file_path, reverse=False): if not line: continue - chars, prop = line.split(';') + chars, prop = line.split(';')[:2] chars = chars.strip() prop = prop.strip() @@ -423,26 +412,6 @@ def parse_ucd(ucd_path): _emoji_zwj_sequences = parse_unicode_datafile( path.join(ucd_path, 'emoji-zwj-sequences.txt')) - # filter modern pentathlon, as it seems likely to be removed from final spec - # also filter rifle - def is_excluded(n): - return n in [0x1f93b, 0x1f946] - - def contains_excluded(t): - if type(t) == int: - return is_excluded(t) - return any(is_excluded(cp) for cp in t) - - # filter modern pentathlon, as it seems likely to be removed from final spec - _emoji_properties['Emoji'] = set( - t for t in _emoji_properties['Emoji'] if not contains_excluded(t)) - _emoji_sequences = dict( - (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t)) - - # add in UN flag - UN_seq = flag_sequence('UN') - _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence' - def flag_sequence(territory_code): return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code) @@ -454,7 +423,8 @@ UNSUPPORTED_FLAGS = frozenset({ flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'), flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'), flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'), - flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'), + flag_sequence('UN'), flag_sequence('WF'), flag_sequence('XK'), + flag_sequence('YT'), }) EQUIVALENT_FLAGS = { @@ -467,6 +437,22 @@ EQUIVALENT_FLAGS = { COMBINING_KEYCAP = 0x20E3 +# Characters that Android defaults to emoji style, different from the recommendations in UTR #51 +ANDROID_DEFAULT_EMOJI = frozenset({ + 0x2600, # BLACK SUN WITH RAYS + 0x2601, # CLOUD + 0x260E, # BLACK TELEPHONE + 0x261D, # WHITE UP POINTING INDEX + 0x263A, # WHITE SMILING FACE + 0x2660, # BLACK SPADE SUIT + 0x2663, # BLACK CLUB SUIT + 0x2665, # BLACK HEART SUIT + 0x2666, # BLACK DIAMOND SUIT + 0x270C, # VICTORY HAND + 0x2744, # SNOWFLAKE + 0x2764, # HEAVY BLACK HEART +}) + LEGACY_ANDROID_EMOJI = { 0xFE4E5: flag_sequence('JP'), 0xFE4E6: flag_sequence('US'), @@ -502,7 +488,17 @@ ZWJ_IDENTICALS = { def is_fitzpatrick_modifier(cp): - return 0x1f3fb <= cp <= 0x1f3ff + return 0x1F3FB <= cp <= 0x1F3FF + + +def reverse_emoji(seq): + rev = list(reversed(seq)) + # if there are fitzpatrick modifiers in the sequence, keep them after + # the emoji they modify + for i in xrange(1, len(rev)): + if is_fitzpatrick_modifier(rev[i-1]): + rev[i], rev[i-1] = rev[i-1], rev[i] + return tuple(rev) def compute_expected_emoji(): @@ -522,15 +518,7 @@ def compute_expected_emoji(): sequence_pieces.update(sequence) # Add reverse of all emoji ZWJ sequences, which are added to the fonts # as a workaround to get the sequences work in RTL text. - reversed_seq = list(reversed(sequence)) - # if there are fitzpatrick modifiers in the sequence, keep them after - # the emoji they modify - for i in xrange(1, len(reversed_seq)): - if is_fitzpatrick_modifier(reversed_seq[i - 1]): - tmp = reversed_seq[i] - reversed_seq[i] = reversed_seq[i-1] - reversed_seq[i-1] = tmp - reversed_seq = tuple(reversed_seq) + reversed_seq = reverse_emoji(sequence) all_sequences.add(reversed_seq) equivalent_emoji[reversed_seq] = sequence @@ -549,6 +537,7 @@ def compute_expected_emoji(): set(LEGACY_ANDROID_EMOJI.keys())) default_emoji = ( _emoji_properties['Emoji_Presentation'] | + ANDROID_DEFAULT_EMOJI | all_sequences | set(LEGACY_ANDROID_EMOJI.keys())) |