diff options
65 files changed, 1090 insertions, 503 deletions
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java index 221923821bbb..aef1d0c31f9d 100644 --- a/core/java/android/app/ActivityTransitionState.java +++ b/core/java/android/app/ActivityTransitionState.java @@ -337,11 +337,12 @@ class ActivityTransitionState { } public void startExitOutTransition(Activity activity, Bundle options) { - if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) { + mEnterTransitionCoordinator = null; + if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) || + mExitTransitionCoordinators == null) { return; } ActivityOptions activityOptions = new ActivityOptions(options); - mEnterTransitionCoordinator = null; if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { int key = activityOptions.getExitCoordinatorKey(); int index = mExitTransitionCoordinators.indexOfKey(key); 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/View.java b/core/java/android/view/View.java index 872168a261e3..20c15a4953d7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20280,8 +20280,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // remove it from the transparent region. final int[] location = attachInfo.mTransparentLocation; getLocationInWindow(location); - region.op(location[0], location[1], location[0] + mRight - mLeft, - location[1] + mBottom - mTop, Region.Op.DIFFERENCE); + // When a view has Z value, then it will be better to leave some area below the view + // for drawing shadow. The shadow outset is proportional to the Z value. Note that + // the bottom part needs more offset than the left, top and right parts due to the + // spot light effects. + int shadowOffset = getZ() > 0 ? (int) getZ() : 0; + region.op(location[0] - shadowOffset, location[1] - shadowOffset, + location[0] + mRight - mLeft + shadowOffset, + location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); } else { if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { // The SKIP_DRAW flag IS set and the background drawable exists, we remove diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 3ff8d4f2e2b1..6933efc15b68 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -6406,16 +6406,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return true; } super.gatherTransparentRegion(region); - final View[] children = mChildren; - final int count = mChildrenCount; + // Instead of naively traversing the view tree, we have to traverse according to the Z + // order here. We need to go with the same order as dispatchDraw(). + // One example is that after surfaceView punch a hole, we will still allow other views drawn + // on top of that hole. In this case, those other views should be able to cut the + // transparent region into smaller area. + final int childrenCount = mChildrenCount; boolean noneOfTheChildrenAreTransparent = true; - for (int i = 0; i < count; i++) { - final View child = children[i]; - if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { - if (!child.gatherTransparentRegion(region)) { - noneOfTheChildrenAreTransparent = false; + if (childrenCount > 0) { + final ArrayList<View> preorderedList = buildOrderedChildList(); + final boolean customOrder = preorderedList == null + && isChildrenDrawingOrderEnabled(); + final View[] children = mChildren; + for (int i = 0; i < childrenCount; i++) { + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { + if (!child.gatherTransparentRegion(region)) { + noneOfTheChildrenAreTransparent = false; + } } } + if (preorderedList != null) preorderedList.clear(); } return meOpaque || noneOfTheChildrenAreTransparent; } 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/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 6432f703f2ba..5935c7889e9c 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1547,7 +1547,7 @@ public class PopupWindow { } // Let the window manager know to align the top to y. - outParams.gravity = Gravity.LEFT | Gravity.TOP; + outParams.gravity = computeGravity(); outParams.width = width; outParams.height = height; 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/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index ef16ef5055de..497600212095 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -20,13 +20,14 @@ #define LOG_TAG "AudioSystem-JNI" #include <utils/Log.h> +#include <sstream> #include <jni.h> #include <JNIHelp.h> #include "core_jni_helpers.h" #include <media/AudioSystem.h> #include <media/AudioPolicy.h> - +#include <nativehelper/ScopedLocalRef.h> #include <system/audio.h> #include <system/audio_policy.h> #include "android_media_AudioFormat.h" @@ -903,6 +904,12 @@ static bool hasFormat(int* formats, size_t size, int format) { return false; // not found } +// TODO: pull out to separate file +template <typename T, size_t N> +static constexpr size_t array_size(const T (&)[N]) { + return N; +} + static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort, const struct audio_port *nAudioPort) { @@ -923,6 +930,38 @@ static jint convertAudioPortFromNative(JNIEnv *env, ALOGV("convertAudioPortFromNative id %d role %d type %d name %s", nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name); + // Verify audio port array count info. + if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates) + || nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks) + || nAudioPort->num_formats > array_size(nAudioPort->formats) + || nAudioPort->num_gains > array_size(nAudioPort->gains)) { + + std::stringstream ss; + ss << "convertAudioPortFromNative array count out of bounds:" + << " num_sample_rates " << nAudioPort->num_sample_rates + << " num_channel_masks " << nAudioPort->num_channel_masks + << " num_formats " << nAudioPort->num_formats + << " num_gains " << nAudioPort->num_gains + ; + std::string s = ss.str(); + + // Prefer to log through Java wtf instead of native ALOGE. + ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log")); + jmethodID jWtfId = (jLogClass.get() == nullptr) + ? nullptr + : env->GetStaticMethodID(jLogClass.get(), "wtf", + "(Ljava/lang/String;Ljava/lang/String;)I"); + if (jWtfId != nullptr) { + ScopedLocalRef<jstring> jMessage(env, env->NewStringUTF(s.c_str())); + ScopedLocalRef<jstring> jTag(env, env->NewStringUTF(LOG_TAG)); + (void)env->CallStaticIntMethod(jLogClass.get(), jWtfId, jTag.get(), jMessage.get()); + } else { + ALOGE("%s", s.c_str()); + } + jStatus = (jint)AUDIO_JAVA_ERROR; + goto exit; + } + jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates); if (jSamplingRates == NULL) { jStatus = (jint)AUDIO_JAVA_ERROR; @@ -1066,7 +1105,7 @@ static jint convertAudioPortFromNative(JNIEnv *env, &jAudioPortConfig, &nAudioPort->active_config); if (jStatus != AUDIO_JAVA_SUCCESS) { - return jStatus; + goto exit; } env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ed71fc2f4a8e..3339d02d9bbe 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -183,6 +183,7 @@ <protected-broadcast android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" /> <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" /> <protected-broadcast android:name="android.btopp.intent.action.LIST" /> @@ -199,6 +200,8 @@ <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" /> <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" /> <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" /> + <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" /> + <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" /> <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" /> @@ -394,6 +397,8 @@ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" /> <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" /> + <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" /> + <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" /> <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" /> <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" /> <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" /> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 8023edffdb47..350caaab8fa6 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -598,7 +598,7 @@ <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string> <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string> <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa (ppal.)"</string> - <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string> + <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string> <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string> <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Outro fax"</string> <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index bebe027cb67f..10c583637f59 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1362,7 +1362,7 @@ <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string> <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string> <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string> - <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string> + <string name="storage_internal" msgid="3570990907910199483">"אחסון שיתוף פנימי"</string> <string name="storage_sd_card" msgid="3282948861378286745">"כרטיס SD"</string> <string name="storage_sd_card_label" msgid="6347111320774379257">"כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb_drive" msgid="6261899683292244209">"כונן USB"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 5b446b445a0f..8bd7160d16b8 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1310,7 +1310,7 @@ <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string> <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string> <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string> - <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string> + <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장용량"</string> <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string> <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string> <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 0f82dcbdffcf..58c2c8a2f219 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1197,8 +1197,7 @@ <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string> <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string> <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string> - <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) --> - <skip /> + <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string> <string name="ime_action_go" msgid="8320845651737369027">"Өтүү"</string> <string name="ime_action_search" msgid="658110271822807811">"Издөө"</string> @@ -1229,10 +1228,8 @@ <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</string> <string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string> <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string> - <!-- no translation found for vpn_text (1610714069627824309) --> - <skip /> - <!-- no translation found for vpn_text_long (4907843483284977618) --> - <skip /> + <string name="vpn_text" msgid="1610714069627824309">"Тармактын параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string> + <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string> diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml new file mode 100644 index 000000000000..bdf83016d18e --- /dev/null +++ b/core/res/res/values-mcc232-mnc10/config.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + ** Copyright 2016, 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. + */ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23203</item> + <item>23205</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml new file mode 100644 index 000000000000..2c14f87374f6 --- /dev/null +++ b/core/res/res/values-mcc232-mnc13/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + ** Copyright 2016, 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. + */ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23203</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml new file mode 100644 index 000000000000..77f64199a80b --- /dev/null +++ b/core/res/res/values-mcc302-mnc500/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + ** Copyright 2016, 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. + */ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>302</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml new file mode 100644 index 000000000000..77f64199a80b --- /dev/null +++ b/core/res/res/values-mcc302-mnc510/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + ** Copyright 2016, 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. + */ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>302</item> + </string-array> +</resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index ae115d877588..5a356d54b456 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1310,7 +1310,7 @@ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string> <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string> <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string> - <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string> + <string name="storage_internal" msgid="3570990907910199483">"Armazen. interno partilhado"</string> <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string> <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string> 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/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index c836204486b0..0f305f3cff3d 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -144,6 +144,55 @@ import java.util.ArrayList; * android:valueType="pathType"/> * </set> * </pre></li> + * <p> + * Since AAPT tool is now supporting a new format which can bundle several related XML files into + * one, we can merge the previous example into one XML file, like this: + * </p> + * <pre> + * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" > + * <aapt:attr name="android:drawable"> + * <vector + * android:height="64dp" + * android:width="64dp" + * android:viewportHeight="600" + * android:viewportWidth="600" > + * <group + * android:name="rotationGroup" + * android:pivotX="300.0" + * android:pivotY="300.0" + * android:rotation="45.0" > + * <path + * android:name="v" + * android:fillColor="#000000" + * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + * </group> + * </vector> + * </aapt:attr> + * + * <target android:name="rotationGroup"> * + * <aapt:attr name="android:animation"> + * <objectAnimator + * android:duration="6000" + * android:propertyName="rotation" + * android:valueFrom="0" + * android:valueTo="360" /> + * </aapt:attr> + * </target> + * + * <target android:name="v" > + * <aapt:attr name="android:animation"> + * <set> + * <objectAnimator + * android:duration="3000" + * android:propertyName="pathData" + * android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + * android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" + * android:valueType="pathType"/> + * </set> + * </aapt:attr> + * </target> + * </animated-vector> + * </pre> * * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index dc1d18f3b2bd..9ff69650294d 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -27,9 +27,9 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Insets; import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; -import android.graphics.PorterDuff.Mode; import android.graphics.Shader; import android.util.ArrayMap; import android.util.AttributeSet; @@ -140,12 +140,16 @@ import dalvik.system.VMRuntime; * in the SVG's path data. This is defined in the viewport space.</dd> * <dt><code>android:fillColor</code></dt> * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list - * or a gradient color. If this property is animated, any value set by the animation will - * override the original value. No path fill is drawn if this property is not specified.</dd> + * or a gradient color (See {@link android.R.styleable#GradientColor} + * and {@link android.R.styleable#GradientColorItem}). + * If this property is animated, any value set by the animation will override the original value. + * No path fill is drawn if this property is not specified.</dd> * <dt><code>android:strokeColor</code></dt> * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color - * state list or a gradient color. If this property is animated, any value set by the animation will - * override the original value. No path outline is drawn if this property is not specified.</dd> + * state list or a gradient color (See {@link android.R.styleable#GradientColor} + * and {@link android.R.styleable#GradientColorItem}). + * If this property is animated, any value set by the animation will override the original value. + * No path outline is drawn if this property is not specified.</dd> * <dt><code>android:strokeWidth</code></dt> * <dd>The width a path stroke.</dd> * <dt><code>android:strokeAlpha</code></dt> @@ -166,8 +170,9 @@ import dalvik.system.VMRuntime; * <dt><code>android:strokeMiterLimit</code></dt> * <dd>Sets the Miter limit for a stroked path.</dd> * <dt><code>android:fillType</code></dt> - * <dd>Sets the fillType for a path. It is the same as SVG's "fill-rule" properties. - * For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty</dd> + * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the + * same as SVG's "fill-rule" properties. For more details, see + * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd> * </dl></dd> * </dl> * @@ -201,7 +206,26 @@ import dalvik.system.VMRuntime; * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> * </group> * </vector> - * </pre></li> + * </pre> + * </li> + * <li>And here is an example of linear gradient color, which is supported in SDK 24+. + * See more details in {@link android.R.styleable#GradientColor} and + * {@link android.R.styleable#GradientColorItem}. + * <pre> + * <gradient xmlns:android="http://schemas.android.com/apk/res/android" + * android:angle="90" + * android:startColor="?android:attr/colorPrimary" + * android:endColor="?android:attr/colorControlActivated" + * android:centerColor="#f00" + * android:startX="0" + * android:startY="0" + * android:endX="100" + * android:endY="100" + * android:type="linear"> + * </gradient> + * </pre> + * </li> + * */ public class VectorDrawable extends Drawable { 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/CaptivePortalLogin/res/values-bn-rBD/strings.xml b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml index 20173b0dc3bf..24cbfbd6430e 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/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java index 14d4e2d942d9..02a912734239 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/Events.java +++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java @@ -53,7 +53,8 @@ public final class Events { */ public static boolean isTouchType(int toolType) { return toolType == MotionEvent.TOOL_TYPE_FINGER - || toolType == MotionEvent.TOOL_TYPE_STYLUS; + || toolType == MotionEvent.TOOL_TYPE_STYLUS + || toolType == MotionEvent.TOOL_TYPE_UNKNOWN; } /** 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/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 7d42211be5e5..682af8bd536f 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -863,4 +863,7 @@ <!-- Label for Help and feedback menu item --> <string name="help_feedback_label">Help & feedback</string> + <!-- Content description for drawer menu button [CHAR_LIMIT=30]--> + <string name="content_description_menu_button">Menu</string> + </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 6658c14bd1cd..a50b366c26ac 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -226,6 +226,7 @@ public class SettingsDrawerActivity extends Activity { public void showMenuIcon() { mShowingMenu = true; getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu); + getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button); getActionBar().setDisplayHomeAsUpEnabled(true); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java index 284827b57929..aae9cf6de797 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java @@ -29,7 +29,6 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.SparseArray; import android.widget.TextView; - import com.android.settingslib.R; public class AccessPointPreference extends Preference { @@ -44,13 +43,14 @@ public class AccessPointPreference extends Preference { private final StateListDrawable mWifiSld; private final int mBadgePadding; private final UserBadgeCache mBadgeCache; - private TextView mTitleView; + private boolean mForSavedNetworks = false; private AccessPoint mAccessPoint; private Drawable mBadge; private int mLevel; private CharSequence mContentDescription; + private int mDefaultIconResId; static final int[] WIFI_CONNECTION_STRENGTH = { R.string.accessibility_wifi_one_bar, @@ -85,6 +85,24 @@ public class AccessPointPreference extends Preference { refresh(); } + public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache, + int iconResId, boolean forSavedNetworks) { + super(context); + mBadgeCache = cache; + mAccessPoint = accessPoint; + mForSavedNetworks = forSavedNetworks; + mAccessPoint.setTag(this); + mLevel = -1; + mDefaultIconResId = iconResId; + + mWifiSld = (StateListDrawable) context.getTheme() + .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0); + + // Distance from the end of the title at which this AP's user badge should sit. + mBadgePadding = context.getResources() + .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding); + } + public AccessPoint getAccessPoint() { return mAccessPoint; } @@ -112,7 +130,7 @@ public class AccessPointPreference extends Preference { protected void updateIcon(int level, Context context) { if (level == -1) { - setIcon(null); + safeSetDefaultIcon(); } else { if (getIcon() == null) { // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then @@ -124,16 +142,24 @@ public class AccessPointPreference extends Preference { ? STATE_SECURED : STATE_NONE); Drawable drawable = mWifiSld.getCurrent(); - if (!mForSavedNetworks) { + if (!mForSavedNetworks && drawable != null) { setIcon(drawable); - } else { - setIcon(null); + return; } } + safeSetDefaultIcon(); } } } + private void safeSetDefaultIcon() { + if (mDefaultIconResId != 0) { + setIcon(mDefaultIconResId); + } else { + setIcon(null); + } + } + protected void updateBadge(Context context) { WifiConfiguration config = mAccessPoint.getConfig(); if (config != null) { 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/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index b5b0cd86f397..4caeba84b202 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -875,7 +875,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } synchronized (this) { - if (isOpRestricted(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1024,7 +1024,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } Op op = getOpLocked(ops, code, true); - if (isOpRestricted(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName)) { return AppOpsManager.MODE_IGNORED; } if (op.duration == -1) { @@ -1082,7 +1082,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } Op op = getOpLocked(ops, code, true); - if (isOpRestricted(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { return AppOpsManager.MODE_IGNORED; } final int switchCode = AppOpsManager.opToSwitch(code); @@ -1308,7 +1308,7 @@ public class AppOpsService extends IAppOpsService.Stub { return op; } - private boolean isOpRestricted(int uid, int code, String packageName) { + private boolean isOpRestrictedLocked(int uid, int code, String packageName) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2210,24 +2210,32 @@ public class AppOpsService extends IAppOpsService.Stub { private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages) { - ClientRestrictionState restrictionState = mOpUserRestrictions.get(token); + boolean notifyChange = false; - if (restrictionState == null) { - try { - restrictionState = new ClientRestrictionState(token); - } catch (RemoteException e) { - return; + synchronized (AppOpsService.this) { + ClientRestrictionState restrictionState = mOpUserRestrictions.get(token); + + if (restrictionState == null) { + try { + restrictionState = new ClientRestrictionState(token); + } catch (RemoteException e) { + return; + } + mOpUserRestrictions.put(token, restrictionState); } - mOpUserRestrictions.put(token, restrictionState); - } - if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) { - notifyWatchersOfChange(code); + if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) { + notifyChange = true; + } + + if (restrictionState.isDefault()) { + mOpUserRestrictions.remove(token); + restrictionState.destroy(); + } } - if (restrictionState.isDefault()) { - mOpUserRestrictions.remove(token); - restrictionState.destroy(); + if (notifyChange) { + notifyWatchersOfChange(code); } } @@ -2263,10 +2271,12 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public void removeUser(int userHandle) throws RemoteException { checkSystemUid("removeUser"); - final int tokenCount = mOpUserRestrictions.size(); - for (int i = tokenCount - 1; i >= 0; i--) { - ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i); - opRestrictions.removeUser(userHandle); + synchronized (AppOpsService.this) { + final int tokenCount = mOpUserRestrictions.size(); + for (int i = tokenCount - 1; i >= 0; i--) { + ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i); + opRestrictions.removeUser(userHandle); + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9e601eb7e07c..ff3f159b1d08 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1158,6 +1158,7 @@ public final class ActivityManagerService extends ActivityManagerNative * For example, references to the commonly used services. */ HashMap<String, IBinder> mAppBindArgs; + HashMap<String, IBinder> mIsolatedAppBindArgs; /** * Temporary to avoid allocations. Protected by main lock. @@ -2935,18 +2936,24 @@ public final class ActivityManagerService extends ActivityManagerNative * lazily setup to make sure the services are running when they're asked for. */ private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) { + // Isolated processes won't get this optimization, so that we don't + // violate the rules about which services they have access to. + if (isolated) { + if (mIsolatedAppBindArgs == null) { + mIsolatedAppBindArgs = new HashMap<>(); + mIsolatedAppBindArgs.put("package", ServiceManager.getService("package")); + } + return mIsolatedAppBindArgs; + } + if (mAppBindArgs == null) { mAppBindArgs = new HashMap<>(); - // Isolated processes won't get this optimization, so that we don't - // violate the rules about which services they have access to. - if (!isolated) { - // Setup the application init args - mAppBindArgs.put("package", ServiceManager.getService("package")); - mAppBindArgs.put("window", ServiceManager.getService("window")); - mAppBindArgs.put(Context.ALARM_SERVICE, - ServiceManager.getService(Context.ALARM_SERVICE)); - } + // Setup the application init args + mAppBindArgs.put("package", ServiceManager.getService("package")); + mAppBindArgs.put("window", ServiceManager.getService("window")); + mAppBindArgs.put(Context.ALARM_SERVICE, + ServiceManager.getService(Context.ALARM_SERVICE)); } return mAppBindArgs; } 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/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java index f98012b39a86..62c9f4c116c2 100644 --- a/services/core/java/com/android/server/os/SchedulingPolicyService.java +++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java @@ -55,7 +55,8 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { Process.setThreadGroup(tid, Binder.getCallingPid() == pid ? Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_AUDIO_APP); // must be in this order or it fails the schedulability constraint - Process.setThreadScheduler(tid, Process.SCHED_FIFO, prio); + Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, + prio); } catch (RuntimeException e) { return PackageManager.PERMISSION_DENIED; } diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 836b588c7621..bff6d2d4786e 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -93,38 +93,39 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (mDexoptCommands != null) { throw new IllegalStateException("already called prepare()"); } + final List<PackageParser.Package> important; + final List<PackageParser.Package> others; synchronized (mPackageManagerService.mPackages) { // Important: the packages we need to run with ab-ota compiler-reason. - List<PackageParser.Package> important = PackageManagerServiceUtils.getPackagesForDexopt( + important = PackageManagerServiceUtils.getPackagesForDexopt( mPackageManagerService.mPackages.values(), mPackageManagerService); // Others: we should optimize this with the (first-)boot compiler-reason. - List<PackageParser.Package> others = - new ArrayList<>(mPackageManagerService.mPackages.values()); + others = new ArrayList<>(mPackageManagerService.mPackages.values()); others.removeAll(important); // Pre-size the array list by over-allocating by a factor of 1.5. mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2); + } - for (PackageParser.Package p : important) { - // Make sure that core apps are optimized according to their own "reason". - // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed - // (by default is speed-profile) they will be interepreted/JITed. This in itself is - // not a problem as we will end up doing profile guided compilation. However, some - // core apps may be loaded by system server which doesn't JIT and we need to make - // sure we don't interpret-only - int compilationReason = p.coreApp - ? PackageManagerService.REASON_CORE_APP - : PackageManagerService.REASON_AB_OTA; - mDexoptCommands.addAll(generatePackageDexopts(p, compilationReason)); - } - for (PackageParser.Package p : others) { - // We assume here that there are no core apps left. - if (p.coreApp) { - throw new IllegalStateException("Found a core app that's not important"); - } - mDexoptCommands.addAll( - generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); + for (PackageParser.Package p : important) { + // Make sure that core apps are optimized according to their own "reason". + // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed + // (by default is speed-profile) they will be interepreted/JITed. This in itself is + // not a problem as we will end up doing profile guided compilation. However, some + // core apps may be loaded by system server which doesn't JIT and we need to make + // sure we don't interpret-only + int compilationReason = p.coreApp + ? PackageManagerService.REASON_CORE_APP + : PackageManagerService.REASON_AB_OTA; + mDexoptCommands.addAll(generatePackageDexopts(p, compilationReason)); + } + for (PackageParser.Package p : others) { + // We assume here that there are no core apps left. + if (p.coreApp) { + throw new IllegalStateException("Found a core app that's not important"); } + mDexoptCommands.addAll( + generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); } completeSize = mDexoptCommands.size(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 6cdc40f7a81c..583128444cfc 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -109,6 +109,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final int installerUid; final SessionParams params; final long createdMillis; + final int defaultContainerGid; /** Staging location where client data is written. */ final File stageDir; @@ -199,13 +200,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { + // Cache package manager data without the lock held + final PackageInfo pkgInfo = mPm.getPackageInfo( + params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId); + final ApplicationInfo appInfo = mPm.getApplicationInfo( + params.appPackageName, 0, userId); + synchronized (mLock) { if (msg.obj != null) { mRemoteObserver = (IPackageInstallObserver2) msg.obj; } try { - commitLocked(); + commitLocked(pkgInfo, appInfo); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); @@ -264,6 +271,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } else { mPermissionsAccepted = false; } + final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE, + PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); + defaultContainerGid = UserHandle.getSharedAppGid(uid); } public SessionInfo generateInfo() { @@ -520,7 +530,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget(); } - private void commitLocked() throws PackageManagerException { + private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo) + throws PackageManagerException { if (mDestroyed) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed"); } @@ -538,7 +549,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Verify that stage looks sane with respect to existing application. // This currently only ensures packageName, versionCode, and certificate // consistency. - validateInstallLocked(); + validateInstallLocked(pkgInfo, appInfo); Preconditions.checkNotNull(mPackageName); Preconditions.checkNotNull(mSignatures); @@ -650,7 +661,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * Note that upgrade compatibility is still performed by * {@link PackageManagerService}. */ - private void validateInstallLocked() throws PackageManagerException { + private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo) + throws PackageManagerException { mPackageName = null; mVersionCode = -1; mSignatures = null; @@ -729,10 +741,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (removeSplitList.size() > 0) { // validate split names marked for removal - final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0; - final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId); for (String splitName : removeSplitList) { - if (!ArrayUtils.contains(pkg.splitNames, splitName)) { + if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Split not found: " + splitName); } @@ -740,11 +750,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // ensure we've got appropriate package name, version code and signatures if (mPackageName == null) { - mPackageName = pkg.packageName; - mVersionCode = pkg.versionCode; + mPackageName = pkgInfo.packageName; + mVersionCode = pkgInfo.versionCode; } if (mSignatures == null) { - mSignatures = pkg.signatures; + mSignatures = pkgInfo.signatures; } } @@ -757,8 +767,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } else { // Partial installs must be consistent with existing install - final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId); - if (app == null) { + if (appInfo == null) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Missing existing base package for " + mPackageName); } @@ -766,8 +775,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final PackageLite existing; final ApkLite existingBase; try { - existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0); - existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()), + existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0); + existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()), PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); @@ -777,7 +786,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Inherit base if not overridden if (mResolvedBaseFile == null) { - mResolvedBaseFile = new File(app.getBaseCodePath()); + mResolvedBaseFile = new File(appInfo.getBaseCodePath()); mResolvedInheritedFiles.add(mResolvedBaseFile); } @@ -794,7 +803,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // Inherit compiled oat directory. - final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile(); + final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile(); mInheritedFilesBase = packageInstallDir; final File oatDir = new File(packageInstallDir, "oat"); if (oatDir.exists()) { @@ -822,7 +831,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException { + private void assertApkConsistent(String tag, ApkLite apk) + throws PackageManagerException { if (!mPackageName.equals(apk.packageName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package " + apk.packageName + " inconsistent with " + mPackageName); @@ -1035,10 +1045,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Failed to finalize container " + cid); } - final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE, - PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); - final int gid = UserHandle.getSharedAppGid(uid); - if (!PackageHelper.fixSdPermissions(cid, gid, null)) { + if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) { throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, "Failed to fix permissions on container " + cid); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f326555ee00a..005c6b36d4cc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8649,7 +8649,9 @@ public class PackageManagerService extends IPackageManager.Stub { for (i=0; i<N; i++) { PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); - if (cur == null) { + final String curPackageName = cur == null ? null : cur.info.packageName; + final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName); + if (cur == null || isPackageUpdate) { mPermissionGroups.put(pg.info.name, pg); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { @@ -8657,6 +8659,9 @@ public class PackageManagerService extends IPackageManager.Stub { } else { r.append(' '); } + if (isPackageUpdate) { + r.append("UPD:"); + } r.append(pg.info.name); } } else { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index c1fc7f114c67..b80775b690e2 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -324,9 +324,29 @@ public class ShortcutService extends IShortcutService.Stub { int CHECK_LAUNCHER_ACTIVITY = 12; int IS_ACTIVITY_ENABLED = 13; int PACKAGE_UPDATE_CHECK = 14; - - int COUNT = PACKAGE_UPDATE_CHECK + 1; - } + int ASYNC_PRELOAD_USER_DELAY = 15; + + int COUNT = ASYNC_PRELOAD_USER_DELAY + 1; + } + + private static final String[] STAT_LABELS = { + "getHomeActivities()", + "Launcher permission check", + "getPackageInfo()", + "getPackageInfo(SIG)", + "getApplicationInfo", + "cleanupDanglingBitmaps", + "getActivity+metadata", + "getInstalledPackages", + "checkPackageChanges", + "getApplicationResources", + "resourceNameLookup", + "getLauncherActivity", + "checkLauncherActivity", + "isActivityEnabled", + "packageUpdateCheck", + "asyncPreloadUserDelay" + }; final Object mStatLock = new Object(); @@ -533,19 +553,26 @@ public class ShortcutService extends IShortcutService.Stub { /** lifecycle event */ void handleUnlockUser(int userId) { if (DEBUG) { - Slog.d(TAG, "handleUnlockUser: user=" + userId); + Slog.d(TAG, "handleUnlockUser: user=" + userId); } synchronized (mLock) { mUnlockedUsers.put(userId, true); - - // Preload the user's shortcuts. - // Also see if the locale has changed. - // Note as of nyc, the locale is per-user, so the locale shouldn't change - // when the user is locked. However due to b/30119489 it still happens. - getUserShortcutsLocked(userId).detectLocaleChange(); - - checkPackageChanges(userId); } + + // Preload the user data. + // Note, we don't use mHandler here but instead just start a new thread. + // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very + // busy at this point and this could take hundreds of milliseconds, which would be too + // late since the launcher would already have started. + // So we just create a new thread. This code runs rarely, so we don't use a thread pool + // or anything. + final long start = injectElapsedRealtime(); + injectRunOnNewThread(() -> { + synchronized (mLock) { + logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start); + getUserShortcutsLocked(userId); + } + }); } /** lifecycle event */ @@ -1110,6 +1137,9 @@ public class ShortcutService extends IShortcutService.Stub { userPackages = new ShortcutUser(this, userId); } mUsers.put(userId, userPackages); + + // Also when a user's data is first accessed, scan all packages. + checkPackageChanges(userId); } return userPackages; } @@ -1468,6 +1498,10 @@ public class ShortcutService extends IShortcutService.Stub { mHandler.post(r); } + void injectRunOnNewThread(Runnable r) { + new Thread(r).start(); + } + /** * @throws IllegalArgumentException if {@code numShortcuts} is bigger than * {@link #getMaxActivityShortcuts()}. @@ -3218,23 +3252,9 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(" Stats:"); synchronized (mStatLock) { - final String p = " "; - dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()"); - dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check"); - - dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()"); - dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)"); - dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo"); - dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps"); - dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata"); - dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages"); - dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges"); - dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources"); - dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup"); - dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity"); - dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity"); - dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled"); - dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck"); + for (int i = 0; i < Stats.COUNT; i++) { + dumpStatLS(pw, " ", i); + } } pw.println(); @@ -3277,12 +3297,12 @@ public class ShortcutService extends IShortcutService.Stub { return tobj.format("%Y-%m-%d %H:%M:%S"); } - private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) { + private void dumpStatLS(PrintWriter pw, String prefix, int statId) { pw.print(prefix); final int count = mCountStats[statId]; final long dur = mDurationStats[statId]; pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms", - label, count, dur, + STAT_LABELS[statId], count, dur, (count == 0 ? 0 : ((double) dur) / count))); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8da3a7d7639d..a39add80ba8f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -7756,6 +7756,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final WindowState w = mTopFullscreenOpaqueWindowState; + if (w != mFocusedWindow) { + return false; + } // We only enable seamless rotation if the top window has requested // it and is in the fullscreen opaque state. Seamless rotation diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f2f85bf184cf..1f82f0cda9f6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2908,12 +2908,11 @@ public class WindowManagerService extends IWindowManager.Stub } result |= RELAYOUT_RES_SURFACE_CHANGED; } - final WindowSurfaceController surfaceController = winAnimator.mSurfaceController; - if (viewVisibility == View.VISIBLE && surfaceController != null) { + if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) { // We already told the client to go invisible, but the message may not be // handled yet, or it might want to draw a last frame. If we already have a // surface, let the client use that, but don't create new surface at this point. - surfaceController.getSurface(outSurface); + winAnimator.mSurfaceController.getSurface(outSurface); } else { if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win); 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/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 1c7a138468cf..e96e97bcaa02 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -390,6 +390,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } @Override + void injectRunOnNewThread(Runnable r) { + runOnHandler(r); + } + + @Override void injectEnforceCallingPermission(String permission, String message) { if (!mCallerPermissions.contains(permission)) { throw new SecurityException("Missing permission: " + permission); @@ -921,6 +926,12 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { }); } + protected void setPackageLastUpdateTime(String packageName, long value) { + updatePackageInfo(packageName, pi -> { + pi.lastUpdateTime = value; + }); + } + protected void uninstallPackage(int userId, String packageName) { if (ENABLE_DUMP) { Log.v(TAG, "Unnstall package " + packageName + " / " + userId); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 253334eec9cf..ed4e391a6273 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -3945,11 +3945,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mInjectedPackages.remove(CALLING_PACKAGE_1); mInjectedPackages.remove(CALLING_PACKAGE_3); - mService.handleUnlockUser(USER_0); + mService.checkPackageChanges(USER_0); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); // --------------- assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); @@ -3961,7 +3961,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); - mService.handleUnlockUser(USER_10); + mService.checkPackageChanges(USER_10); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); @@ -4154,7 +4154,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_1, 1); // Then send the broadcast, to only user-0. - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); waitOnMainThread(); @@ -4186,10 +4186,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mInjectedCurrentTimeMillis = START_TIME + 200; mRunningUsers.put(USER_10, true); + mUnlockedUsers.put(USER_10, true); reset(c0); reset(c10); + setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis); mService.handleUnlockUser(USER_10); + mService.checkPackageChanges(USER_10); waitOnMainThread(); @@ -4221,7 +4224,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Then send the broadcast, to only user-0. mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0)); - mService.handleUnlockUser(USER_10); + mService.checkPackageChanges(USER_10); waitOnMainThread(); @@ -4243,9 +4246,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_3, 100); // Then send the broadcast, to only user-0. - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0)); - mService.handleUnlockUser(USER_10); + mService.checkPackageChanges(USER_10); waitOnMainThread(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 43d2a1f1156c..a04034e3f764 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -535,6 +535,18 @@ public class VoiceInteractionManagerService extends SystemService { + " user=" + userHandle); } + ComponentName getCurAssistant(int userHandle) { + String curAssistant = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.ASSISTANT, userHandle); + if (TextUtils.isEmpty(curAssistant)) { + return null; + } + if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant + + " user=" + userHandle); + return ComponentName.unflattenFromString(curAssistant); + } + void resetCurAssistant(int userHandle) { Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.ASSISTANT, null, userHandle); @@ -1178,6 +1190,7 @@ public class VoiceInteractionManagerService extends SystemService { synchronized (VoiceInteractionManagerServiceStub.this) { ComponentName curInteractor = getCurInteractor(userHandle); ComponentName curRecognizer = getCurRecognizer(userHandle); + ComponentName curAssistant = getCurAssistant(userHandle); if (curRecognizer == null) { // Could a new recognizer appear when we don't have one pre-installed? if (anyPackagesAppearing()) { @@ -1196,6 +1209,7 @@ public class VoiceInteractionManagerService extends SystemService { // the default config. setCurInteractor(null, userHandle); setCurRecognizer(null, userHandle); + resetCurAssistant(userHandle); initForUser(userHandle); return; } @@ -1212,6 +1226,20 @@ public class VoiceInteractionManagerService extends SystemService { return; } + if (curAssistant != null) { + int change = isPackageDisappearing(curAssistant.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE) { + // If the currently set assistant is being removed, then we should + // reset back to the default state (which is probably that we prefer + // to have the default full voice interactor enabled). + setCurInteractor(null, userHandle); + setCurRecognizer(null, userHandle); + resetCurAssistant(userHandle); + initForUser(userHandle); + return; + } + } + // There is no interactor, so just deal with a simple recognizer. int change = isPackageDisappearing(curRecognizer.getPackageName()); if (change == PACKAGE_PERMANENT_CHANGE diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 4da5ff28204e..a093d54568d3 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -461,6 +461,32 @@ public abstract class Connection extends Conferenceable { */ public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED"; + /** + * Connection event used to inform {@link InCallService}s when a call has been put on hold by + * the remote party. + * <p> + * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the + * call is being held locally on the device. When a capable {@link ConnectionService} receives + * signalling to indicate that the remote party has put the call on hold, it can send this + * connection event. + * @hide + */ + public static final String EVENT_CALL_REMOTELY_HELD = + "android.telecom.event.CALL_REMOTELY_HELD"; + + /** + * Connection event used to inform {@link InCallService}s when a call which was remotely held + * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party. + * <p> + * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the + * call is being held locally on the device. When a capable {@link ConnectionService} receives + * signalling to indicate that the remote party has taken the call off hold, it can send this + * connection event. + * @hide + */ + public static final String EVENT_CALL_REMOTELY_UNHELD = + "android.telecom.event.CALL_REMOTELY_UNHELD"; + // Flag controlling whether PII is emitted into the logs private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py index 2956d87f247c..7ec46a3ee86b 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(): @@ -511,26 +507,52 @@ def compute_expected_emoji(): all_sequences = set() all_sequences.update(_emoji_variation_sequences) + # add zwj sequences not in the current emoji-zwj-sequences.txt + adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences) + adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences) + # single parent families + additional_emoji_zwj = ( + (0x1F468, 0x200D, 0x1F466), + (0x1F468, 0x200D, 0x1F467), + (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466), + (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466), + (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467), + (0x1F469, 0x200D, 0x1F466), + (0x1F469, 0x200D, 0x1F467), + (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466), + (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466), + (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467), + ) + # sequences formed from man and woman and optional fitzpatrick modifier + modified_extensions = ( + 0x2696, + 0x2708, + 0x1F3A8, + 0x1F680, + 0x1F692, + ) + for seq in additional_emoji_zwj: + adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' + for ext in modified_extensions: + for base in (0x1F468, 0x1F469): + seq = (base, 0x200D, ext) + adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' + for modifier in range(0x1F3FB, 0x1F400): + seq = (base, modifier, 0x200D, ext) + adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' + for sequence in _emoji_sequences.keys(): sequence = tuple(ch for ch in sequence if ch != EMOJI_VS) all_sequences.add(sequence) sequence_pieces.update(sequence) - for sequence in _emoji_zwj_sequences.keys(): + for sequence in adjusted_emoji_zwj_sequences.keys(): sequence = tuple(ch for ch in sequence if ch != EMOJI_VS) all_sequences.add(sequence) 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 +571,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())) diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 9d0c20ce4c5d..d3d5ea05c1af 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -817,6 +817,7 @@ public class WifiConfiguration implements Parcelable { */ public static final int NETWORK_SELECTION_ENABLE = 0; /** + * @deprecated it is not used any more. * This network is disabled because higher layer (>2) network is bad */ public static final int DISABLED_BAD_LINK = 1; @@ -862,7 +863,7 @@ public class WifiConfiguration implements Parcelable { */ private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = { "NETWORK_SELECTION_ENABLE", - "NETWORK_SELECTION_DISABLED_BAD_LINK", + "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ", "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE", "NETWORK_SELECTION_DISABLED_DHCP_FAILURE", |