diff options
52 files changed, 512 insertions, 141 deletions
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index e21392cb8ce6..511aec331055 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -122,6 +122,12 @@ void CountMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId); } + +void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { + flushIfNeededLocked(dumpTimeNs); + mPastBuckets.clear(); +} + void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, ProtoOutputStream* protoOutput) { diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index cafc882308d4..8e94a75d9f57 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -59,6 +59,8 @@ private: const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) override; + void clearPastBucketsLocked(const int64_t dumpTimeNs) override; + // Internal interface to handle condition change. void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override; diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index 3661b31d9ee4..561049249fb7 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -438,6 +438,11 @@ void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) { mPastBuckets.clear(); } +void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { + flushIfNeededLocked(dumpTimeNs); + mPastBuckets.clear(); +} + void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, ProtoOutputStream* protoOutput) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 80fbdde2df09..f755294cd1c3 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -65,6 +65,8 @@ private: const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) override; + void clearPastBucketsLocked(const int64_t dumpTimeNs) override; + // Internal interface to handle condition change. void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index 2f2679efab65..23f780adb01e 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -100,6 +100,10 @@ std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked(ProtoOutputStream& pr return buffer; } +void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { + mProto->clear(); +} + void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, ProtoOutputStream* protoOutput) { diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index 5c2917400b10..23302c4063b8 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -49,6 +49,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) override; + void clearPastBucketsLocked(const int64_t dumpTimeNs) override; // Internal interface to handle condition change. void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 12708567043b..005cb7117d6b 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -160,6 +160,12 @@ void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { } } +void GaugeMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { + flushIfNeededLocked(dumpTimeNs); + mPastBuckets.clear(); + mSkippedBuckets.clear(); +} + void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, ProtoOutputStream* protoOutput) { diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index 71d5912df6ae..8af2f3632e02 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -91,6 +91,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) override; + void clearPastBucketsLocked(const int64_t dumpTimeNs) override; // for testing GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric, diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 532ecbf36d72..42396490b3d3 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -119,6 +119,11 @@ public: return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, protoOutput); } + void clearPastBuckets(const int64_t dumpTimeNs) { + std::lock_guard<std::mutex> lock(mMutex); + return clearPastBucketsLocked(dumpTimeNs); + } + void dumpStates(FILE* out, bool verbose) const { std::lock_guard<std::mutex> lock(mMutex); dumpStatesLocked(out, verbose); @@ -177,6 +182,7 @@ protected: virtual void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) = 0; + virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0; virtual size_t byteSizeLocked() const = 0; virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0; diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 47a1a86f861f..0d3aebfd46a5 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -201,6 +201,8 @@ void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS); producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, protoOutput); protoOutput->end(token); + } else { + producer->clearPastBuckets(dumpTimeStampNs); } } for (const auto& annotation : mAnnotations) { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 27fd78f4ed94..506cf383e036 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -151,6 +151,12 @@ void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) { mPastBuckets.clear(); } +void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { + flushIfNeededLocked(dumpTimeNs); + mPastBuckets.clear(); + mSkippedBuckets.clear(); +} + void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, ProtoOutputStream* protoOutput) { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 8df30d3de284..64604c2f674f 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -89,6 +89,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, android::util::ProtoOutputStream* protoOutput) override; + void clearPastBucketsLocked(const int64_t dumpTimeNs) override; // Internal interface to handle condition change. void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c5b80196cf26..725f2405f954 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5102,6 +5102,10 @@ public class Notification implements Parcelable savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER)); publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNT_DOWN, savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN)); + String appName = savedBundle.getString(EXTRA_SUBSTITUTE_APP_NAME); + if (appName != null) { + publicExtras.putString(EXTRA_SUBSTITUTE_APP_NAME, appName); + } mN.extras = publicExtras; RemoteViews view; if (ambient) { diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index ac21395c2fa7..7a6b72e980f5 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -848,7 +848,11 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - return service.getRemoteName(this); + String name = service.getRemoteName(this); + if (name != null) { + return name.replaceAll("[\\t\\n\\r]+", " "); + } + return null; } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 206ed719a55b..dec2cd42c5f9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3659,6 +3659,10 @@ public class Intent implements Parcelable, Cloneable { * <p class="note">This is a protected intent that can only be sent by the system. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable} and the helper + * functions {@code ServiceStateTable.getUriForSubscriptionIdAndField} and + * {@code ServiceStateTable.getUriForSubscriptionId} to subscribe to changes to the ServiceState + * for a given subscription id and field with a ContentObserver or using JobScheduler. */ @Deprecated @SystemApi @@ -3674,6 +3678,7 @@ public class Intent implements Parcelable, Cloneable { * @see android.telephony.ServiceState#STATE_POWER_OFF * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_REG_STATE}. */ @Deprecated @SystemApi @@ -3687,6 +3692,7 @@ public class Intent implements Parcelable, Cloneable { * @see android.telephony.ServiceState#STATE_POWER_OFF * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_REG_STATE}. */ @Deprecated @SystemApi @@ -3697,6 +3703,7 @@ public class Intent implements Parcelable, Cloneable { * type. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_ROAMING_TYPE}. */ @Deprecated @SystemApi @@ -3707,6 +3714,7 @@ public class Intent implements Parcelable, Cloneable { * type. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_ROAMING_TYPE}. */ @Deprecated @SystemApi @@ -3718,6 +3726,8 @@ public class Intent implements Parcelable, Cloneable { * {@code null} if the operator name is not known or unregistered. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_ALPHA_LONG}. */ @Deprecated @SystemApi @@ -3729,6 +3739,8 @@ public class Intent implements Parcelable, Cloneable { * {@code null} if the operator name is not known or unregistered. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_ALPHA_SHORT}. */ @Deprecated @SystemApi @@ -3740,6 +3752,7 @@ public class Intent implements Parcelable, Cloneable { * network. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_NUMERIC}. */ @Deprecated @SystemApi @@ -3751,6 +3764,8 @@ public class Intent implements Parcelable, Cloneable { * {@code null} if the operator name is not known or unregistered. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_ALPHA_LONG}. */ @Deprecated @SystemApi @@ -3762,6 +3777,8 @@ public class Intent implements Parcelable, Cloneable { * {@code null} if the operator name is not known or unregistered. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_ALPHA_SHORT}. */ @Deprecated @SystemApi @@ -3773,6 +3790,7 @@ public class Intent implements Parcelable, Cloneable { * data operator. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_NUMERIC}. */ @Deprecated @SystemApi @@ -3784,6 +3802,8 @@ public class Intent implements Parcelable, Cloneable { * Will be {@code true} if manual mode, {@code false} if automatic mode. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#IS_MANUAL_NETWORK_SELECTION}. */ @Deprecated @SystemApi @@ -3794,6 +3814,8 @@ public class Intent implements Parcelable, Cloneable { * radio technology. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#RIL_VOICE_RADIO_TECHNOLOGY}. */ @Deprecated @SystemApi @@ -3804,6 +3826,8 @@ public class Intent implements Parcelable, Cloneable { * radio technology. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#RIL_DATA_RADIO_TECHNOLOGY}. */ @Deprecated @SystemApi @@ -3815,6 +3839,7 @@ public class Intent implements Parcelable, Cloneable { * Will be {@code true} if support, {@code false} otherwise. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#CSS_INDICATOR}. */ @Deprecated @SystemApi @@ -3825,6 +3850,7 @@ public class Intent implements Parcelable, Cloneable { * id. {@code Integer.MAX_VALUE} if unknown. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#NETWORK_ID}. */ @Deprecated @SystemApi @@ -3835,6 +3861,7 @@ public class Intent implements Parcelable, Cloneable { * {@code Integer.MAX_VALUE} if unknown. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#SYSTEM_ID}. */ @Deprecated @SystemApi @@ -3845,6 +3872,7 @@ public class Intent implements Parcelable, Cloneable { * indicator if registered on a CDMA or EVDO system or {@code -1} if not. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#CDMA_ROAMING_INDICATOR}. */ @Deprecated @SystemApi @@ -3855,6 +3883,8 @@ public class Intent implements Parcelable, Cloneable { * indicator from the PRL if registered on a CDMA or EVDO system {@code -1} if not. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#CDMA_DEFAULT_ROAMING_INDICATOR}. */ @Deprecated @SystemApi @@ -3866,6 +3896,7 @@ public class Intent implements Parcelable, Cloneable { * {@code true} if in emergency only mode, {@code false} otherwise. * @hide * @removed + * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#IS_EMERGENCY_ONLY}. */ @Deprecated @SystemApi @@ -3877,6 +3908,8 @@ public class Intent implements Parcelable, Cloneable { * {@code true} if registration indicates roaming, {@code false} otherwise * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#IS_DATA_ROAMING_FROM_REGISTRATION}. */ @Deprecated @SystemApi @@ -3889,6 +3922,8 @@ public class Intent implements Parcelable, Cloneable { * {@code true} if carrier aggregation is in use, {@code false} otherwise. * @hide * @removed + * @deprecated Use + * {@link android.provider.Telephony.ServiceStateTable#IS_USING_CARRIER_AGGREGATION}. */ @Deprecated @SystemApi diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java index 6e510607754a..baa7a502688e 100644 --- a/core/java/android/hardware/radio/RadioMetadata.java +++ b/core/java/android/hardware/radio/RadioMetadata.java @@ -269,6 +269,29 @@ public final class RadioMetadata implements Parcelable { mBundle = in.readBundle(); } + @Override + public String toString() { + StringBuilder sb = new StringBuilder("RadioMetadata["); + + final String removePrefix = "android.hardware.radio.metadata"; + + boolean first = true; + for (String key : mBundle.keySet()) { + if (first) first = false; + else sb.append(", "); + + String keyDisp = key; + if (key.startsWith(removePrefix)) keyDisp = key.substring(removePrefix.length()); + + sb.append(keyDisp); + sb.append('='); + sb.append(mBundle.get(key)); + } + + sb.append("]"); + return sb.toString(); + } + /** * Returns {@code true} if the given key is contained in the meta data * diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 848c59610720..f17e0f026fda 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -77,10 +77,18 @@ public final class Looper { private Printer mLogging; private long mTraceTag; - /* If set, the looper will show a warning log if a message dispatch takes longer than time. */ + /** + * If set, the looper will show a warning log if a message dispatch takes longer than this. + */ private long mSlowDispatchThresholdMs; - /** Initialize the current thread as a looper. + /** + * If set, the looper will show a warning log if a message delivery (actual delivery time - + * post time) takes longer than this. + */ + private long mSlowDeliveryThresholdMs; + + /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling @@ -138,6 +146,16 @@ public final class Looper { Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); + // Allow overriding a threshold with a system prop. e.g. + // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' + final int thresholdOverride = + SystemProperties.getInt("log.looper." + + Process.myUid() + "." + + Thread.currentThread().getName() + + ".slow", 0); + + boolean slowDeliveryDetected = false; + for (;;) { Message msg = queue.next(); // might block if (msg == null) { @@ -152,30 +170,50 @@ public final class Looper { msg.callback + ": " + msg.what); } - final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; - final long traceTag = me.mTraceTag; + long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; + long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; + if (thresholdOverride > 0) { + slowDispatchThresholdMs = thresholdOverride; + slowDeliveryThresholdMs = thresholdOverride; + } + final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); + final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); + + final boolean needStartTime = logSlowDelivery || logSlowDispatch; + final boolean needEndTime = logSlowDispatch; + if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } - final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); - final long end; + + final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; + final long dispatchEnd; try { msg.target.dispatchMessage(msg); - end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); + dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } - if (slowDispatchThresholdMs > 0) { - final long time = end - start; - if (time > slowDispatchThresholdMs) { - Slog.w(TAG, "Dispatch took " + time + "ms on " - + Thread.currentThread().getName() + ", h=" + - msg.target + " cb=" + msg.callback + " msg=" + msg.what); + if (logSlowDelivery) { + if (slowDeliveryDetected) { + if ((dispatchStart - msg.when) <= 10) { + Slog.w(TAG, "Drained"); + slowDeliveryDetected = false; + } + } else { + if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", + msg)) { + // Once we write a slow delivery log, suppress until the queue drains. + slowDeliveryDetected = true; + } } } + if (logSlowDispatch) { + showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); + } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); @@ -196,6 +234,19 @@ public final class Looper { } } + private static boolean showSlowLog(long threshold, long measureStart, long measureEnd, + String what, Message msg) { + final long actualTime = measureEnd - measureStart; + if (actualTime < threshold) { + return false; + } + // For slow delivery, the current message isn't really important, but log it anyway. + Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms " + + Thread.currentThread().getName() + " h=" + + msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what); + return true; + } + /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. @@ -243,9 +294,13 @@ public final class Looper { mTraceTag = traceTag; } - /** {@hide} */ - public void setSlowDispatchThresholdMs(long slowDispatchThresholdMs) { + /** + * Set a thresholds for slow dispatch/delivery log. + * {@hide} + */ + public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) { mSlowDispatchThresholdMs = slowDispatchThresholdMs; + mSlowDeliveryThresholdMs = slowDeliveryThresholdMs; } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 7e5464761e38..db34856e0ad6 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -700,15 +700,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb mIsCreating = false; if (mSurfaceControl != null && !mSurfaceCreated) { mSurface.release(); - // If we are not in the stopped state, then the destruction of the Surface - // represents a visual change we need to display, and we should go ahead - // and destroy the SurfaceControl. However if we are in the stopped state, - // we can just leave the Surface around so it can be a part of animations, - // and we let the life-time be tied to the parent surface. - if (!mWindowStopped) { - mSurfaceControl.destroy(); - mSurfaceControl = null; - } + + mSurfaceControl.destroy(); + mSurfaceControl = null; } } } catch (Exception ex) { diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java index 7558f8cee233..eada142dd3c6 100644 --- a/core/java/com/android/internal/os/BackgroundThread.java +++ b/core/java/com/android/internal/os/BackgroundThread.java @@ -18,12 +18,15 @@ package com.android.internal.os; import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; import android.os.Trace; /** * Shared singleton background thread for each process. */ public final class BackgroundThread extends HandlerThread { + private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000; + private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000; private static BackgroundThread sInstance; private static Handler sHandler; @@ -35,7 +38,10 @@ public final class BackgroundThread extends HandlerThread { if (sInstance == null) { sInstance = new BackgroundThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); + final Looper looper = sInstance.getLooper(); + looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); + looper.setSlowLogThresholdMs( + SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index be834987e73f..7703052bc327 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -4084,7 +4084,8 @@ public class BatteryStatsImpl extends BatteryStats { boolean ensureStartClockTime(final long currentTime) { final long ABOUT_ONE_YEAR = 365*24*60*60*1000L; - if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) { + if ((currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) + || (mStartClockTime > currentTime)) { // If the start clock time has changed by more than a year, then presumably // the previous time was completely bogus. So we are going to figure out a // new time based on how much time has elapsed since we started counting. diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java index eac9f64f3fa0..cd80d53a7546 100644 --- a/core/java/com/android/internal/policy/DecorContext.java +++ b/core/java/com/android/internal/policy/DecorContext.java @@ -23,6 +23,8 @@ import android.view.ContextThemeWrapper; import android.view.WindowManager; import android.view.WindowManagerImpl; +import java.lang.ref.WeakReference; + /** * Context for decor views which can be seeded with pure application context and not depend on the * activity, but still provide some of the facilities that Activity has, @@ -35,9 +37,12 @@ class DecorContext extends ContextThemeWrapper { private WindowManager mWindowManager; private Resources mActivityResources; - public DecorContext(Context context, Resources activityResources) { + private WeakReference<Context> mActivityContext; + + public DecorContext(Context context, Context activityContext) { super(context, null); - mActivityResources = activityResources; + mActivityContext = new WeakReference<>(activityContext); + mActivityResources = activityContext.getResources(); } void setPhoneWindow(PhoneWindow phoneWindow) { @@ -60,6 +65,13 @@ class DecorContext extends ContextThemeWrapper { @Override public Resources getResources() { + Context activityContext = mActivityContext.get(); + // Attempt to update the local cached Resources from the activity context. If the activity + // is no longer around, return the old cached values. + if (activityContext != null) { + mActivityResources = activityContext.getResources(); + } + return mActivityResources; } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index eadefc919934..cc95df7724ba 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -41,7 +41,6 @@ import java.util.List; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -55,7 +54,6 @@ import android.graphics.Region; import android.graphics.Shader; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.os.RemoteException; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; @@ -1844,6 +1842,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } @Override + public Resources getResources() { + // Make sure the Resources object is propogated from the Context since it can be updated in + // the Context object. + return getContext().getResources(); + } + + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 528888fbaab6..7ea023eb50b2 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -2299,7 +2299,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (applicationContext == null) { context = getContext(); } else { - context = new DecorContext(applicationContext, getContext().getResources()); + context = new DecorContext(applicationContext, getContext()); if (mTheme != -1) { context.setTheme(mTheme); } diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 7ecd9ab8cc42..c7b65ef578db 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -632,7 +632,7 @@ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.--> <dimen name="notification_media_image_max_width_low_ram">100dp</dimen> <!-- The size of the right icon image when on low ram --> - <dimen name="notification_right_icon_size_low_ram">38dp</dimen> + <dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen> <dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen> diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index bf91a16cb3b7..6d5276f2423e 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -118,7 +118,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { @Test public void installPlatformSignedFrameworkOverlayAndUpdate() throws Exception { - assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource")); + assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectFrameworkResource")); installPackage("OverlayHostTests_FrameworkOverlayV1.apk"); setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true); @@ -138,6 +138,27 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { "expectFrameworkOverlayV2Resource")); } + @Test + public void enabledFrameworkOverlayMustAffectNewlyInstalledPackage() throws Exception { + try { + setPackageEnabled(DEVICE_TEST_PKG, false); + + installPackage("OverlayHostTests_FrameworkOverlayV1.apk"); + setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true); + assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME)); + + setPackageEnabled(DEVICE_TEST_PKG, true); + assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, + "expectFrameworkOverlayV1Resource")); + } finally { + setPackageEnabled(DEVICE_TEST_PKG, true); + } + } + + private void setPackageEnabled(String pkg, boolean enabled) throws Exception { + getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg); + } + private void setOverlayEnabled(String pkg, boolean enabled) throws Exception { getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg); } diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java index d46bb378971d..a174d774b80e 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java @@ -61,7 +61,7 @@ public class UpdateOverlayTest { } @Test - public void expectFrameworkOverlayResource() throws Exception { + public void expectFrameworkResource() throws Exception { assertEquals("OK", mResources.getString(android.R.string.ok)); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index ce34d0b3b7cc..727b62b4b79d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -82,14 +82,14 @@ public class KeyguardStatusView extends GridLayout implements @Override public void onTimeChanged() { - refresh(); + refreshTime(); } @Override public void onKeyguardVisibilityChanged(boolean showing) { if (showing) { if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); - refresh(); + refreshTime(); updateOwnerInfo(); updateLogoutView(); } @@ -107,7 +107,7 @@ public class KeyguardStatusView extends GridLayout implements @Override public void onUserSwitchComplete(int userId) { - refresh(); + refreshFormat(); updateOwnerInfo(); updateLogoutView(); } @@ -184,7 +184,7 @@ public class KeyguardStatusView extends GridLayout implements boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive(); setEnableMarquee(shouldMarquee); - refresh(); + refreshFormat(); updateOwnerInfo(); updateLogoutView(); updateDark(); @@ -289,9 +289,10 @@ public class KeyguardStatusView extends GridLayout implements mClockView.refresh(); } - private void refresh() { + private void refreshFormat() { Patterns.update(mContext); - refreshTime(); + mClockView.setFormat12Hour(Patterns.clockView12); + mClockView.setFormat24Hour(Patterns.clockView24); } public int getLogoutButtonHeight() { @@ -338,6 +339,11 @@ public class KeyguardStatusView extends GridLayout implements } @Override + public void onLocaleListChanged() { + refreshFormat(); + } + + @Override public boolean hasOverlappingRendering() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index a7975d7e4595..087d481a61f2 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1380,6 +1380,15 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, mHardwareLayout = HardwareUiLayout.get(mListView); mHardwareLayout.setOutsideTouchListener(view -> dismiss()); setTitle(R.string.global_actions); + mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public boolean dispatchPopulateAccessibilityEvent( + View host, AccessibilityEvent event) { + // Populate the title here, just as Activity does + event.getText().add(mContext.getString(R.string.global_actions)); + return true; + } + }); } private void updateList() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 1d64088099ec..9a1d180242a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1896,6 +1896,13 @@ public class StatusBar extends SystemUI implements DemoMode, } } + if (!panelsEnabled()) { + if (DEBUG) { + Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey()); + } + return false; + } + if (sbn.getNotification().fullScreenIntent != null) { if (mAccessibilityManager.isTouchExplorationEnabled()) { if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey()); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index d7aedc4e53f1..b5071de6125f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -742,8 +742,11 @@ public class VolumeDialogImpl implements VolumeDialog { updateVolumeRowH(row); } updateRingerH(); - mWindow.setTitle(mContext.getString(R.string.volume_dialog_title, - getStreamLabelH(getActiveRow().ss))); + mWindow.setTitle(composeWindowTitle()); + } + + CharSequence composeWindowTitle() { + return mContext.getString(R.string.volume_dialog_title, getStreamLabelH(getActiveRow().ss)); } private void updateVolumeRowH(VolumeRow row) { @@ -1214,6 +1217,13 @@ public class VolumeDialogImpl implements VolumeDialog { } @Override + public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { + // Activities populate their title here. Follow that example. + event.getText().add(composeWindowTitle()); + return true; + } + + @Override public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event) { rescheduleTimeoutH(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index d3cb5a6ecd8a..37e00052383c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -443,6 +443,30 @@ public class StatusBarTest extends SysuiTestCase { } @Test + public void testPeek_disabledStatusBar() { + Notification n = new Notification.Builder(getContext(), "a").build(); + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, + UserHandle.of(0), null, 0); + NotificationData.Entry entry = new NotificationData.Entry(sbn); + mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */); + + assertFalse("The panel shouldn't allow peek while disabled", + mStatusBar.shouldPeek(entry, sbn)); + } + + @Test + public void testPeek_disabledNotificationShade() { + Notification n = new Notification.Builder(getContext(), "a").build(); + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, + UserHandle.of(0), null, 0); + NotificationData.Entry entry = new NotificationData.Entry(sbn); + mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */); + + assertFalse("The panel shouldn't allow peek while notitifcation shade disabled", + mStatusBar.shouldPeek(entry, sbn)); + } + + @Test public void testLogHidden() { try { mStatusBar.handleVisibleToUserChanged(false); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 3253f2e40692..51c0488dcd9f 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -219,6 +219,8 @@ public final class AutofillManagerService extends SystemService { final String activePackageName = getActiveAutofillServicePackageName(); if (packageName.equals(activePackageName)) { removeCachedServiceLocked(getChangingUserId()); + } else { + handlePackageUpdateLocked(packageName); } } } @@ -250,6 +252,8 @@ public final class AutofillManagerService extends SystemService { return true; } removeCachedServiceLocked(getChangingUserId()); + } else { + handlePackageUpdateLocked(pkg); } } } @@ -274,6 +278,14 @@ public final class AutofillManagerService extends SystemService { } return serviceComponent.getPackageName(); } + + @GuardedBy("mLock") + private void handlePackageUpdateLocked(String packageName) { + final int size = mServicesCache.size(); + for (int i = 0; i < size; i++) { + mServicesCache.valueAt(i).handlePackageUpdateLocked(packageName); + } + } }; // package changes diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 0bb29a7d1967..e582daa29335 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -626,9 +626,25 @@ final class AutofillManagerServiceImpl { } @GuardedBy("mLock") + void handlePackageUpdateLocked(String packageName) { + final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); + if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) { + resetExtServiceLocked(); + } + } + + @GuardedBy("mLock") + void resetExtServiceLocked() { + if (sVerbose) Slog.v(TAG, "reset autofill service."); + mFieldClassificationStrategy.reset(); + } + + @GuardedBy("mLock") void destroyLocked() { if (sVerbose) Slog.v(TAG, "destroyLocked()"); + resetExtServiceLocked(); + final int numSessions = mSessions.size(); final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions); for (int i = 0; i < numSessions; i++) { diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java index da5220104e3c..9bec856e2308 100644 --- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java +++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java @@ -83,7 +83,7 @@ final class FieldClassificationStrategy { } @Nullable - private ServiceInfo getServiceInfo() { + ServiceInfo getServiceInfo() { final String packageName = mContext.getPackageManager().getServicesSystemSharedLibraryPackageName(); if (packageName == null) { @@ -119,6 +119,18 @@ final class FieldClassificationStrategy { return name; } + void reset() { + synchronized (mLock) { + if (mServiceConnection != null) { + if (sDebug) Slog.d(TAG, "reset(): unbinding service."); + mContext.unbindService(mServiceConnection); + mServiceConnection = null; + } else { + if (sDebug) Slog.d(TAG, "reset(): service is not bound. Do nothing."); + } + } + } + /** * Run a command, starting the service connection if necessary. */ diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java index 021bfaa10230..fe30057fc820 100644 --- a/services/core/java/com/android/server/FgThread.java +++ b/services/core/java/com/android/server/FgThread.java @@ -17,6 +17,7 @@ package com.android.server; import android.os.Handler; +import android.os.Looper; import android.os.Trace; /** @@ -28,6 +29,9 @@ import android.os.Trace; * to be delayed for a user-noticeable amount of time. */ public final class FgThread extends ServiceThread { + private static final long SLOW_DISPATCH_THRESHOLD_MS = 100; + private static final long SLOW_DELIVERY_THRESHOLD_MS = 200; + private static FgThread sInstance; private static Handler sHandler; @@ -39,7 +43,10 @@ public final class FgThread extends ServiceThread { if (sInstance == null) { sInstance = new FgThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); + final Looper looper = sInstance.getLooper(); + looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); + looper.setSlowLogThresholdMs( + SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java index f81307429ae0..b2fa6846a6d0 100644 --- a/services/core/java/com/android/server/UiThread.java +++ b/services/core/java/com/android/server/UiThread.java @@ -28,6 +28,7 @@ import android.os.Trace; */ public final class UiThread extends ServiceThread { private static final long SLOW_DISPATCH_THRESHOLD_MS = 100; + private static final long SLOW_DELIVERY_THRESHOLD_MS = 200; private static UiThread sInstance; private static Handler sHandler; @@ -48,7 +49,8 @@ public final class UiThread extends ServiceThread { sInstance.start(); final Looper looper = sInstance.getLooper(); looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); - looper.setSlowDispatchThresholdMs(SLOW_DISPATCH_THRESHOLD_MS); + looper.setSlowLogThresholdMs( + SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 16c5969a9167..e73f42fa4264 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1626,6 +1626,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (parent != null) { parent.onActivityStateChanged(this, state, reason); } + + if (state == STOPPING) { + mWindowContainerController.notifyAppStopping(); + } } ActivityState getState() { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index b1ca64eaf7a0..548290e4dec4 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2409,6 +2409,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (stack.isCompatible(windowingMode, activityType)) { return stack; } + if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY + && display.getSplitScreenPrimaryStack() == stack + && candidateTask == stack.topTask()) { + // This is a special case when we try to launch an activity that is currently on + // top of split-screen primary stack, but is targeting split-screen secondary. + // In this case we don't want to move it to another stack. + // TODO(b/78788972): Remove after differentiating between preferred and required + // launch options. + return stack; + } } } diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index e840a29d0937..03d8f395e36e 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -1279,7 +1279,9 @@ public final class ContentService extends IContentService.Stub { case Process.SYSTEM_UID: break; // Okay default: - throw new SecurityException("Invalid extras specified."); + final String msg = "Invalid extras specified."; + Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'"); + throw new SecurityException(msg); } } } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index a55870f41571..5fa42457ac2f 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -68,6 +68,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -454,6 +455,7 @@ public class SyncManager { } }; + private final HandlerThread mThread; private final SyncHandler mSyncHandler; private final SyncManagerConstants mConstants; @@ -604,7 +606,9 @@ public class SyncManager { mSyncAdapters = new SyncAdaptersCache(mContext); - mSyncHandler = new SyncHandler(BackgroundThread.get().getLooper()); + mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND); + mThread.start(); + mSyncHandler = new SyncHandler(mThread.getLooper()); mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() { @Override diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index f403953f892d..0425844bd9e3 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -316,7 +316,7 @@ class AutomaticBrightnessController { return true; } - private void resetShortTermModel() { + public void resetShortTermModel() { mBrightnessMapper.clearUserDataPoints(); mShortTermModelValid = true; mShortTermModelAnchor = -1; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 46e883c44e95..3b35d025f595 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -774,14 +774,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brightness = mScreenBrightnessForVr; } - boolean setBrightnessToOverride = false; if (brightness < 0 && mPowerRequest.screenBrightnessOverride > 0) { brightness = mPowerRequest.screenBrightnessOverride; - // If there's a screen brightness override, we want to reset the brightness to it - // whenever the user changes it, to communicate that these changes aren't taking - // effect. However, for a nicer user experience, we don't do it here, but rather after - // the temporary brightness has been taken into account. - setBrightnessToOverride = true; } final boolean autoBrightnessEnabledInDoze = @@ -804,12 +798,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brightnessIsTemporary = true; } - // Reset the brightness to the screen brightness override to communicate to the user that - // her changes aren't taking effect. - if (setBrightnessToOverride && !brightnessIsTemporary) { - putScreenBrightnessSetting(brightness); - } - final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment(); if (autoBrightnessAdjustmentChanged) { mTemporaryAutoBrightnessAdjustment = Float.NaN; @@ -1452,6 +1440,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (userSwitch) { // Don't treat user switches as user initiated change. mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting; + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.resetShortTermModel(); + } } mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); // We don't bother with a pending variable for VR screen brightness since we just diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 3b8a994c4e87..fd51be577308 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -694,32 +694,25 @@ public final class OverlayManagerService extends SystemService { private final class OverlayChangeListener implements OverlayManagerServiceImpl.OverlayChangeListener { @Override - public void onChanged(@NonNull final String targetPackageName, final int userId, - boolean targetChanged, boolean overlayChanged) { + public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) { schedulePersistSettings(); FgThread.getHandler().post(() -> { - // Update the targets' overlays if a change to the target or an overlay occurs - if (targetChanged || overlayChanged) { - updateAssets(userId, targetPackageName); - } + updateAssets(userId, targetPackageName); - // Create the broadcast if the overlay changes - if (overlayChanged) { - final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED, - Uri.fromParts("package", targetPackageName, null)); - intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED, + Uri.fromParts("package", targetPackageName, null)); + intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (DEBUG) { - Slog.d(TAG, "send broadcast " + intent); - } + if (DEBUG) { + Slog.d(TAG, "send broadcast " + intent); + } - try { - ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, - null, null, null, android.app.AppOpsManager.OP_NONE, null, false, - false, userId); - } catch (RemoteException e) { - // Intentionally left empty. - } + try { + ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, + null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false, + userId); + } catch (RemoteException e) { + // Intentionally left empty. } }); } diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index a487ae970821..c57f97b61f2e 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -207,7 +207,9 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, 0); + if (updateAllOverlaysForTarget(packageName, userId, 0)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageChanged(@NonNull final String packageName, final int userId) { @@ -215,7 +217,9 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, 0); + if (updateAllOverlaysForTarget(packageName, userId, 0)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) { @@ -224,7 +228,9 @@ final class OverlayManagerServiceImpl { + userId); } - updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING); + if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) { @@ -232,7 +238,9 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, 0); + if (updateAllOverlaysForTarget(packageName, userId, 0)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageRemoved(@NonNull final String packageName, final int userId) { @@ -240,17 +248,21 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, 0); + if (updateAllOverlaysForTarget(packageName, userId, 0)) { + mListener.onOverlaysChanged(packageName, userId); + } } /** - * Calls OverlayChangeListener#onChanged if the settings for the overlay target were modified, - * and calls OverlayChangeListener#onTargetChanged to signal a change in the target package that - * requires updating target overlays. + * Update the state of any overlays for this target. + * + * Returns true if the system should refresh the app's overlay paths (i.e. + * if the settings were modified for this target, or there is at least one + * enabled framework overlay). */ - private void updateAllOverlaysForTarget(@NonNull final String targetPackageName, + private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName, final int userId, final int flags) { - boolean overlayModified = false; + boolean modified = false; final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId); final int N = ois.size(); for (int i = 0; i < N; i++) { @@ -258,19 +270,22 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId); if (overlayPackage == null) { - overlayModified |= mSettings.remove(oi.packageName, oi.userId); + modified |= mSettings.remove(oi.packageName, oi.userId); removeIdmapIfPossible(oi); } else { try { - overlayModified |= updateState(targetPackageName, oi.packageName, userId, flags); + modified |= updateState(targetPackageName, oi.packageName, userId, flags); } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to update settings", e); - overlayModified |= mSettings.remove(oi.packageName, userId); + modified |= mSettings.remove(oi.packageName, userId); } } } - mListener.onChanged(targetPackageName, userId, /* targetChanged */ true, overlayModified); + // check for enabled framework overlays + modified = modified || !getEnabledOverlayPackageNames("android", userId).isEmpty(); + + return modified; } void onOverlayPackageAdded(@NonNull final String packageName, final int userId) { @@ -291,8 +306,7 @@ final class OverlayManagerServiceImpl { overlayPackage.overlayCategory); try { if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) { - mListener.onChanged(overlayPackage.overlayTarget, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to update settings", e); @@ -308,8 +322,7 @@ final class OverlayManagerServiceImpl { try { final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); if (updateState(oi.targetPackageName, packageName, userId, 0)) { - mListener.onChanged(oi.targetPackageName, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(oi.targetPackageName, userId); } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to update settings", e); @@ -326,8 +339,7 @@ final class OverlayManagerServiceImpl { final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_UPGRADING)) { removeIdmapIfPossible(oi); - mListener.onChanged(oi.targetPackageName, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(oi.targetPackageName, userId); } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to update settings", e); @@ -361,8 +373,7 @@ final class OverlayManagerServiceImpl { } if (updateState(pkg.overlayTarget, packageName, userId, 0)) { - mListener.onChanged(pkg.overlayTarget, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(pkg.overlayTarget, userId); } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to update settings", e); @@ -376,8 +387,7 @@ final class OverlayManagerServiceImpl { removeIdmapIfPossible(overlayInfo); if (overlayInfo.isEnabled()) { // Only trigger updates if the overlay was enabled. - mListener.onChanged(overlayInfo.targetPackageName, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId); } } } catch (OverlayManagerSettings.BadKeyException e) { @@ -425,8 +435,7 @@ final class OverlayManagerServiceImpl { modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0); if (modified) { - mListener.onChanged(oi.targetPackageName, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(oi.targetPackageName, userId); } return true; } catch (OverlayManagerSettings.BadKeyException e) { @@ -485,8 +494,7 @@ final class OverlayManagerServiceImpl { modified |= updateState(targetPackageName, packageName, userId, 0); if (modified) { - mListener.onChanged(targetPackageName, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(targetPackageName, userId); } return true; } catch (OverlayManagerSettings.BadKeyException e) { @@ -519,8 +527,7 @@ final class OverlayManagerServiceImpl { } if (mSettings.setPriority(packageName, newParentPackageName, userId)) { - mListener.onChanged(overlayPackage.overlayTarget, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); } return true; } @@ -540,8 +547,7 @@ final class OverlayManagerServiceImpl { } if (mSettings.setHighestPriority(packageName, userId)) { - mListener.onChanged(overlayPackage.overlayTarget, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); } return true; } @@ -561,8 +567,7 @@ final class OverlayManagerServiceImpl { } if (mSettings.setLowestPriority(packageName, userId)) { - mListener.onChanged(overlayPackage.overlayTarget, userId, - /* targetChanged */ false, /* overlayChanged */ true); + mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); } return true; } @@ -693,8 +698,7 @@ final class OverlayManagerServiceImpl { } interface OverlayChangeListener { - void onChanged(@NonNull String targetPackage, int userId, - boolean targetChanged, boolean overlayChanged); + void onOverlaysChanged(@NonNull String targetPackage, int userId); } interface PackageManagerHelper { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bb1f5c02f864..144f28988a1c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8429,7 +8429,7 @@ public class PackageManagerService extends IPackageManager.Stub // Delete invalid userdata apps if ((scanFlags & SCAN_AS_SYSTEM) == 0 && - errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) { + errorCode != PackageManager.INSTALL_SUCCEEDED) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + parseResult.scanFile); removeCodePathLI(parseResult.scanFile); diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 20283a792cfb..a492672f0ea5 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -719,13 +719,14 @@ final class Notifier { * Plays the wireless charging sound for both wireless and non-wireless charging */ private void playChargingStartedSound() { - // TODO (b/77912907): add back charging sound enabled check & default to charging sounds ON + final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0; final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) == Settings.Global.ZEN_MODE_OFF; final String soundPath = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.CHARGING_STARTED_SOUND); - if (dndOff && soundPath != null) { + if (enabled && dndOff && soundPath != null) { final Uri soundUri = Uri.parse("file://" + soundPath); if (soundUri != null) { final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 165a409028d6..644e3c3c732b 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -671,6 +671,17 @@ public class AppWindowContainerController } } + public void notifyAppStopping() { + synchronized(mWindowMap) { + if (mContainer == null) { + Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " + + mToken); + return; + } + mContainer.detachChildren(); + } + } + public void notifyAppStopped() { synchronized(mWindowMap) { if (mContainer == null) { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index a9560e65db09..966ca4104710 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -913,12 +913,16 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // try and clean up it's child surfaces. We need to prevent this from // happening, so we sever the children, transfering their ownership // from the client it-self to the parent surface (owned by us). + detachChildren(); + + mPendingRelaunchCount++; + } + + void detachChildren() { for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowState w = mChildren.get(i); w.mWinAnimator.detachChildren(); } - - mPendingRelaunchCount++; } void finishRelaunching() { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 6b13edd072cd..efc4e737b92c 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -317,7 +317,7 @@ class TaskSnapshotController { @VisibleForTesting int getSnapshotMode(Task task) { final AppWindowToken topChild = task.getTopChild(); - if (!task.isActivityTypeStandardOrUndefined()) { + if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) { return SNAPSHOT_MODE_NONE; } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) { return SNAPSHOT_MODE_APP_THEME; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 74b40ba23518..1880e9fa362c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -156,6 +156,9 @@ public final class SystemServer { // give any timezone code room without going into negative time. private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000; + private static final long SLOW_DISPATCH_THRESHOLD_MS = 100; + private static final long SLOW_DELIVERY_THRESHOLD_MS = 200; + /* * Implementation class names. TODO: Move them to a codegen class or load * them from the build system somehow. @@ -396,6 +399,8 @@ public final class SystemServer { android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper(); + Looper.getMainLooper().setSlowLogThresholdMs( + SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); // Initialize native services. System.loadLibrary("android_servers"); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 9daea1afc505..1415ada5fc92 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -19,51 +19,44 @@ package com.android.server.am; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; - import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; + import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.am.ActivityStackSupervisor + .MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.ArgumentMatchers.any; - -import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.WaitResult; -import android.content.ComponentName; -import android.content.res.Configuration; import android.graphics.Rect; -import android.hardware.display.DisplayManager; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import android.util.SparseIntArray; -import org.junit.runner.RunWith; import org.junit.Before; import org.junit.Test; - +import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; /** * Tests for the {@link ActivityStackSupervisor} class. @@ -378,4 +371,28 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked( true /* considerKeyguardState */)); } + + /** + * Verify that split-screen primary stack will be chosen if activity is launched that targets + * split-screen secondary, but a matching existing instance is found on top of split-screen + * primary stack. + */ + @Test + public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() throws Exception { + // Create primary split-screen stack with a task and an activity. + final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay() + .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); + final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build(); + + // Find a launch stack for the top activity in split-screen primary, while requesting + // split-screen secondary. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); + final ActivityStack result = mSupervisor.getLaunchStack(r, options, task, true /* onTop */); + + // Assert that the primary stack is returned. + assertEquals(primaryStack, result); + } } diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index f1653ce6c2ae..f2438b833d90 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -2900,12 +2900,30 @@ public final class Telephony { * @hide */ public static final int OWNED_BY_DPC = 0; + /** * Possible value for the OWNED_BY field. * APN is owned by other sources. * @hide */ public static final int OWNED_BY_OTHERS = 1; + + /** + * The APN set id. When the user manually selects an APN or the framework sets an APN as + * preferred, all APNs with the same set id as the selected APN should be prioritized over + * APNs in other sets. + * @hide + */ + public static final String APN_SET_ID = "apn_set_id"; + + /** + * Possible value for the APN_SET_ID field. By default APNs will not belong to a set. If the + * user manually selects an APN with no set set, there is no need to prioritize any specific + * APN set ids. + * @hide + */ + public static final int NO_SET_SET = 0; + } /** |