Merge "Remove unneeded pipeline check"
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e21392c..511aec3 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -122,6 +122,12 @@
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 cafc882..8e94a75 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -59,6 +59,8 @@
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 3661b31..5610492 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -438,6 +438,11 @@
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 80fbdde..f755294 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -65,6 +65,8 @@
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 2f2679e..23f780a 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -100,6 +100,10 @@
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 5c29174..23302c4 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -49,6 +49,7 @@
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 1270856..005cb71 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -160,6 +160,12 @@
}
}
+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 71d5912..8af2f36 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -91,6 +91,7 @@
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 532ecbf..4239649 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -119,6 +119,11 @@
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 @@
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 47a1a86..0d3aebf 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -201,6 +201,8 @@
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 27fd78f..506cf38 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -151,6 +151,12 @@
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 8df30d3..64604c2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -89,6 +89,7 @@
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 f18b92a..9c1c700 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5104,6 +5104,10 @@
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/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1b6b5a0..1b9e27c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -394,6 +394,58 @@
public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
/**
+ * Device only has a display.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_OUT = 0;
+
+ /**
+ * Device has a display and the ability to input Yes/No.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_IO = 1;
+
+ /**
+ * Device only has a keyboard for entry but no display.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_IN = 2;
+
+ /**
+ * Device has no Input or Output capability.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_NONE = 3;
+
+ /**
+ * Device has a display and a full keyboard.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_KBDISP = 4;
+
+ /**
+ * Maximum range value for Input/Output capabilities.
+ *
+ * <p>This should be updated when adding a new Input/Output capability. Other code
+ * like validation depends on this being accurate.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_MAX = 5;
+
+ /**
+ * The Input/Output capability of the device is unknown.
+ *
+ * @hide
+ */
+ public static final int IO_CAPABILITY_UNKNOWN = 255;
+
+ /**
* Broadcast Action: The local Bluetooth adapter has started the remote
* device discovery process.
* <p>This usually involves an inquiry scan of about 12 seconds, followed
@@ -1225,6 +1277,106 @@
}
/**
+ * Returns the Input/Output capability of the device for classic Bluetooth.
+ *
+ * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+ * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
+ * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public int getIoCapability() {
+ if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getIoCapability();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage(), e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+ }
+
+ /**
+ * Sets the Input/Output capability of the device for classic Bluetooth.
+ *
+ * <p>Changing the Input/Output capability of a device only takes effect on restarting the
+ * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
+ * and {@link BluetoothAdapter#enable()} to see the changes.
+ *
+ * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+ * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
+ * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setIoCapability(int capability) {
+ if (getState() != STATE_ON) return false;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.setIoCapability(capability);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage(), e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the Input/Output capability of the device for BLE operations.
+ *
+ * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+ * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
+ * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public int getLeIoCapability() {
+ if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getLeIoCapability();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage(), e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+ }
+
+ /**
+ * Sets the Input/Output capability of the device for BLE operations.
+ *
+ * <p>Changing the Input/Output capability of a device only takes effect on restarting the
+ * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
+ * and {@link BluetoothAdapter#enable()} to see the changes.
+ *
+ * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+ * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
+ * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setLeIoCapability(int capability) {
+ if (getState() != STATE_ON) return false;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.setLeIoCapability(capability);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage(), e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
+ }
+
+ /**
* Get the current Bluetooth scan mode of the local Bluetooth adapter.
* <p>The Bluetooth scan mode determines if the local adapter is
* connectable and/or discoverable from remote Bluetooth devices.
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index 6e51060..baa7a50 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -269,6 +269,29 @@
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/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index eac9f64..cd80d53 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.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 @@
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 @@
@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 6bf2e0e..a186f1a 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1849,6 +1849,13 @@
}
@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/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 3af3e2a..a3c7a9e 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -344,7 +344,7 @@
if (dockedSide == DOCKED_LEFT) {
position += mInsets.left;
} else if (dockedSide == DOCKED_RIGHT) {
- position = mDisplayWidth - position - mInsets.right;
+ position = mDisplayWidth - position - mInsets.right - mDividerSize;
}
}
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f090aca..64a8f9f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2298,7 +2298,7 @@
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/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index ff3452c..0fd0136 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -28,7 +28,6 @@
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
@@ -40,7 +39,6 @@
import java.util.Objects;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class CursorAnchorInfoTest {
private static final float EPSILON = 0.0000001f;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 52df338..9edbf3e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -26,7 +26,6 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.LargeTest;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -37,7 +36,6 @@
import org.junit.runner.RunWith;
@LargeTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputMethodInfoTest {
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index ff71c00..8df1848 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -30,7 +29,6 @@
import java.util.ArrayList;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputMethodSubtypeArrayTest {
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index 2c85ce7..c76359e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -35,7 +34,6 @@
import java.util.Objects;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputMethodSubtypeTest {
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index c7b5933..8c96b58 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -23,7 +23,6 @@
import android.graphics.RectF;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
@@ -34,7 +33,6 @@
import java.util.Objects;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class SparseRectFArrayTest {
// A test data for {@link SparseRectFArray}. null represents the gap of indices.
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 0429d99..13d6749 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -23,7 +23,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodInfo;
@@ -41,7 +40,6 @@
import java.util.List;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputMethodSubtypeSwitchingControllerTest {
private static final String DUMMY_PACKAGE_NAME = "dummy package name";
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index a49e203..3064afa 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -37,7 +37,6 @@
import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -54,7 +53,6 @@
import java.util.Objects;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputMethodUtilsTest {
private static final boolean IS_AUX = true;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
index 1269ffd..549511a 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import android.os.LocaleList;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -30,7 +29,6 @@
import java.util.Locale;
@SmallTest
-@Presubmit
@RunWith(AndroidJUnit4.class)
public class LocaleUtilsTest {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index be7d663..569de76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -40,7 +40,6 @@
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
- SkSafeUnref(mColorFilter);
setTransform(nullptr);
mRenderState.unregisterDeferredLayerUpdater(this);
destroyLayer();
@@ -67,8 +66,11 @@
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
mAlpha = PaintUtils::getAlphaDirect(paint);
mMode = PaintUtils::getBlendModeDirect(paint);
- SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
- SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+ if (paint) {
+ mColorFilter = paint->refColorFilter();
+ } else {
+ mColorFilter.reset();
+ }
}
void DeferredLayerUpdater::apply() {
@@ -143,7 +145,7 @@
#endif
mSurfaceTexture->getTransformMatrix(transform);
- updateLayer(forceFilter, transform);
+ updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
}
}
@@ -153,17 +155,19 @@
Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
- updateLayer(false, identityMatrix.data);
+ updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
vkLayer->updateTexture();
}
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
+ android_dataspace dataspace) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
+ mLayer->setDataSpace(dataspace);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9dc029f..fe3ee7a 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
#include <cutils/compiler.h>
#include <gui/GLConsumer.h>
+#include <system/graphics.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -41,7 +42,7 @@
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode, bool blend)>
CreateLayerFn;
ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
@@ -96,7 +97,7 @@
void detachSurfaceTexture();
- void updateLayer(bool forceFilter, const float* textureTransform);
+ void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
void destroyLayer();
@@ -109,7 +110,7 @@
int mWidth = 0;
int mHeight = 0;
bool mBlend = false;
- SkColorFilter* mColorFilter = nullptr;
+ sk_sp<SkColorFilter> mColorFilter;
int mAlpha = 255;
SkBlendMode mMode = SkBlendMode::kSrcOver;
sp<GLConsumer> mSurfaceTexture;
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 32a3014..42ae29d 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,7 +32,7 @@
namespace uirenderer {
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 1b09191..28749a0 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -32,7 +32,7 @@
class GlLayer : public Layer {
public:
GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
uint32_t getWidth() const override { return texture.mWidth; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 86950d5..fb8f033 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,34 +18,58 @@
#include "renderstate/RenderState.h"
-#include <SkColorFilter.h>
+#include <SkToSRGBColorFilter.h>
namespace android {
namespace uirenderer {
-Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
, mApi(api)
- , colorFilter(nullptr)
+ , mColorFilter(colorFilter)
, alpha(alpha)
, mode(mode) {
// TODO: This is a violation of Android's typical ref counting, but it
// preserves the old inc/dec ref locations. This should be changed...
incStrong(nullptr);
-
+ buildColorSpaceWithFilter();
renderState.registerLayer(this);
}
Layer::~Layer() {
- SkSafeUnref(colorFilter);
-
mRenderState.unregisterLayer(this);
}
-void Layer::setColorFilter(SkColorFilter* filter) {
- SkRefCnt_SafeAssign(colorFilter, filter);
+void Layer::setColorFilter(sk_sp<SkColorFilter> filter) {
+ if (filter != mColorFilter) {
+ mColorFilter = filter;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::setDataSpace(android_dataspace dataspace) {
+ if (dataspace != mCurrentDataspace) {
+ mCurrentDataspace = dataspace;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::buildColorSpaceWithFilter() {
+ sk_sp<SkColorFilter> colorSpaceFilter;
+ sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace);
+ if (colorSpace && !colorSpace->isSRGB()) {
+ colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+ }
+
+ if (mColorFilter && colorSpaceFilter) {
+ mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter);
+ } else if (colorSpaceFilter) {
+ mColorSpaceWithFilter = colorSpaceFilter;
+ } else {
+ mColorSpaceWithFilter = mColorFilter;
+ }
}
void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6921381..89bcddc 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,8 @@
#include <GpuMemoryTracker.h>
#include <utils/RefBase.h>
+#include <SkColorFilter.h>
+#include <SkColorSpace.h>
#include <SkBlendMode.h>
#include <SkPaint.h>
@@ -72,9 +74,15 @@
inline SkBlendMode getMode() const { return mode; }
- inline SkColorFilter* getColorFilter() const { return colorFilter; }
+ inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
- void setColorFilter(SkColorFilter* filter);
+ void setColorFilter(sk_sp<SkColorFilter> filter);
+
+ void setDataSpace(android_dataspace dataspace);
+
+ void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+ inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
inline mat4& getTexTransform() { return texTransform; }
@@ -87,18 +95,30 @@
void postDecStrong();
protected:
- Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+ Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha,
SkBlendMode mode);
RenderState& mRenderState;
private:
+ void buildColorSpaceWithFilter();
+
Api mApi;
/**
* Color filter used to draw this layer. Optional.
*/
- SkColorFilter* colorFilter;
+ sk_sp<SkColorFilter> mColorFilter;
+
+ /**
+ * Colorspace of the contents of the layer. Optional.
+ */
+ android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN;
+
+ /**
+ * A color filter that is the combination of the mColorFilter and mColorSpace. Optional.
+ */
+ sk_sp<SkColorFilter> mColorSpaceWithFilter;
/**
* Indicates raster data backing the layer is scaled, requiring filtration.
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index f23f472..e9664d0 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -28,7 +28,7 @@
class VkLayer : public Layer {
public:
VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
, mWidth(layerWidth)
, mHeight(layerHeight)
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 896c01c..00ba7130 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -50,9 +50,13 @@
GlLayer* glLayer = static_cast<GlLayer*>(layer);
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
- SkASSERT(GL_RGBA == glLayer->getTexture().internalFormat());
- externalTexture.fFormat = GL_RGBA8;
externalTexture.fID = glLayer->getTextureId();
+ // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
+ // expose that info we use it as our default. Further, given that we only use this texture
+ // as a source this will not impact how Skia uses the texture. The only potential affect
+ // this is anticipated to have is that for some format types if we are not bound as an OES
+ // texture we may get invalid results for SKP capture if we read back the texture.
+ externalTexture.fFormat = GL_RGBA8;
GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
@@ -83,7 +87,7 @@
SkPaint paint;
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
- paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
+ paint.setColorFilter(layer->getColorSpaceWithFilter());
const bool nonIdentityMatrix = !matrix.isIdentity();
if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 5b2adbf..cfcfd2b 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -158,7 +158,7 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) {
GlLayer* layer =
new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
layer->generateTexture();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9e73046..d66cba1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -147,6 +147,7 @@
GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
if (cachedContext.get() != currentContext) {
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers (context changed)");
cachedContext->flush();
}
cachedContext.reset(SkSafeRef(currentContext));
@@ -155,6 +156,7 @@
}
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers");
cachedContext->flush();
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 6530074..5825060 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,8 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+ bool blend) {
return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
}
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index b2fccd4..a7ac930 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -72,7 +72,7 @@
layerUpdater->setTransform(&transform);
// updateLayer so it's ready to draw
- layerUpdater->updateLayer(true, Matrix4::identity().data);
+ layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
static_cast<GlLayer*>(layerUpdater->backingLayer())
->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index b8b5050..f29830f 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,7 @@
// push the deferred updates to the layer
Matrix4 scaledMatrix;
scaledMatrix.loadScale(0.5, 0.5, 0.0);
- layerUpdater->updateLayer(true, scaledMatrix.data);
+ layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index c2af867..75740e8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,6 +16,8 @@
#include "Color.h"
+
+#include <utils/Log.h>
#include <cmath>
namespace android {
@@ -53,5 +55,57 @@
return false;
}
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+
+ SkColorSpace::Gamut gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkColorSpace::kSRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkColorSpace::kRec2020_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ gamut = SkColorSpace::kAdobeRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ case HAL_DATASPACE_STANDARD_BT470M:
+ case HAL_DATASPACE_STANDARD_FILM:
+ default:
+ ALOGW("Unsupported Gamut: %d", dataspace);
+ return nullptr;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ default:
+ ALOGW("Unsupported Gamma: %d", dataspace);
+ return nullptr;
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 7ac0d96..2bec1f5 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
#define COLOR_H
#include <math.h>
+#include <system/graphics.h>
#include <SkColor.h>
#include <SkColorSpace.h>
@@ -111,6 +112,8 @@
// approximated with the native sRGB transfer function. This method
// returns true for sRGB, gamma 2.2 and Display P3 for instance
bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 07b980e..ed2f831 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -26,6 +26,10 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -58,6 +62,11 @@
public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+ public static final int NAV_BAR_POS_INVALID = -1;
+ public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
+ public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
+ public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;
+
public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;
public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -141,4 +150,20 @@
Log.w(TAG, "Failed to set recents visibility");
}
}
+
+ /**
+ * @return The side of the screen where navigation bar is positioned.
+ * @see #NAV_BAR_POS_RIGHT
+ * @see #NAV_BAR_POS_LEFT
+ * @see #NAV_BAR_POS_BOTTOM
+ * @see #NAV_BAR_POS_INVALID
+ */
+ public int getNavBarPosition() {
+ try {
+ return WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get nav bar position");
+ }
+ return NAV_BAR_POS_INVALID;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1149ad1..79fea9f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,6 +21,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -364,14 +366,7 @@
if (mStableInsets.isEmpty()) {
SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
}
- int position = (int) (mState.mRatioPositionBeforeMinimized *
- (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
- mSnapAlgorithm = null;
- initializeSnapAlgorithm();
-
- // Set the snap target before minimized but do not save until divider is attached and not
- // minimized because it does not know its minimized state yet.
- mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
+ repositionSnapTargetBeforeMinimized();
}
public WindowManagerProxy getWindowManagerProxy() {
@@ -878,9 +873,36 @@
}
public void notifyDockSideChanged(int newDockSide) {
+ int oldDockSide = mDockSide;
mDockSide = newDockSide;
mMinimizedShadow.setDockSide(mDockSide);
requestLayout();
+
+ // Update the snap position to the new docked side with correct insets
+ SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+ mMinimizedSnapAlgorithm = null;
+ initializeSnapAlgorithm();
+
+ if (oldDockSide == DOCKED_LEFT && mDockSide == DOCKED_RIGHT
+ || oldDockSide == DOCKED_RIGHT && mDockSide == DOCKED_LEFT) {
+ repositionSnapTargetBeforeMinimized();
+ }
+
+ // Landscape to seascape rotation requires minimized to resize docked app correctly
+ if (mHomeStackResizable && mDockedStackMinimized) {
+ resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
+ }
+ }
+
+ private void repositionSnapTargetBeforeMinimized() {
+ int position = (int) (mState.mRatioPositionBeforeMinimized *
+ (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
+ mSnapAlgorithm = null;
+ initializeSnapAlgorithm();
+
+ // Set the snap target before minimized but do not save until divider is attached and not
+ // minimized because it does not know its minimized state yet.
+ mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
}
private void updateDisplayInfo() {
@@ -962,6 +984,12 @@
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
mDockedTaskRect);
+
+ // Move a right-docked-app to line up with the divider while dragging it
+ if (mDockSide == DOCKED_RIGHT) {
+ mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
+ - mDockedTaskRect.left + mDividerSize, 0);
+ }
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
@@ -976,6 +1004,12 @@
calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
mDockSide, mDockedTaskRect);
}
+
+ // Move a docked app if from the right in position with the divider up to insets
+ if (mDockSide == DOCKED_RIGHT) {
+ mDockedTaskRect.offset(Math.max(position,
+ mStableInsets.left) - mDockedTaskRect.left, 0);
+ }
calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
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 1d64088..ff0adb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -24,6 +24,8 @@
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager
.NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -178,6 +180,7 @@
import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -207,14 +210,12 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -1339,8 +1340,15 @@
}
int dockSide = WindowManagerProxy.getInstance().getDockSide();
if (dockSide == WindowManager.DOCKED_INVALID) {
- return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
+ final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
+ if (navbarPos == NAV_BAR_POS_INVALID) {
+ return false;
+ }
+ int createMode = navbarPos == NAV_BAR_POS_LEFT
+ ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
+ : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+ return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
+ null, metricsDockAction);
} else {
Divider divider = getComponent(Divider.class);
if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
@@ -1896,6 +1904,13 @@
}
}
+ 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/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d3cb5a6..37e0005 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 @@
}
@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/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 2465ba2..d869734 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -33,10 +33,11 @@
# It logs the time remaining before the device would've normally gone to sleep without the request.
2731 power_soft_sleep_requested (savedwaketimems|2)
# Power save state has changed. See BatterySaverController.java for the details.
-2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
+2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5),(reason|1|5)
27390 battery_saving_stats (batterySaver|1|5),(interactive|1|5),(doze|1|5),(delta_duration|2|3),(delta_battery_drain|1|1),(delta_battery_drain_percent|1|6),(total_duration|2|3),(total_battery_drain|1|1),(total_battery_drain_percent|1|6)
# Note when the user activity timeout has been overriden by ActivityManagerService
27391 user_activity_timeout_override (override|2|3)
+27392 battery_saver_setting (threshold|1)
#
# Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index e840a29..03d8f39 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 @@
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/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index f403953..0425844 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 @@
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 46e883c..3b35d02 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 @@
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 @@
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 @@
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3003ac..9af02a1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,6 +234,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
+import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -7191,14 +7192,35 @@
}
@Override
- public boolean isDockSideAllowed(int dockSide) {
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation) {
+ final int barPosition = navigationBarPosition(displayWidth, displayHeight, displayRotation);
+ return isDockSideAllowed(dockSide, originalDockSide, barPosition, mNavigationBarCanMove);
+ }
- // We do not allow all dock sides at which the navigation bar touches the docked stack.
- if (!mNavigationBarCanMove) {
- return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
- } else {
- return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
+ @VisibleForTesting
+ static boolean isDockSideAllowed(int dockSide, int originalDockSide,
+ int navBarPosition, boolean navigationBarCanMove) {
+ if (dockSide == DOCKED_TOP) {
+ return true;
}
+
+ if (navigationBarCanMove) {
+ // Only allow the dockside opposite to the nav bar position in landscape
+ return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
+ || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
+ }
+
+ // Side is the same as original side
+ if (dockSide == originalDockSide) {
+ return true;
+ }
+
+ // Only if original docked side was top in portrait will allow left for landscape
+ if (dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP) {
+ return true;
+ }
+ return false;
}
void sendCloseSystemWindows() {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ccbf502..8690a83 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1706,11 +1706,19 @@
DisplayCutout displayCutout, Rect outInsets);
/**
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param dockSide the dockside asking if allowed
+ * @param originalDockSide the side that was original docked to in split screen
* @return True if a specified {@param dockSide} is allowed on the current device, or false
* otherwise. It is guaranteed that at least one dock side for a particular orientation
* is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
+ * If navigation bar is movable then the docked side would bias towards the
+ * {@param originalDockSide}.
*/
- public boolean isDockSideAllowed(int dockSide);
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation);
/**
* Called when the configuration has changed, and it's safe to load new values from resources.
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 20283a7..a492672 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 @@
* 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/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index c527533..cb84cf3 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -90,6 +90,16 @@
*/
private final Plugin[] mPlugins;
+ public static final int REASON_AUTOMATIC_ON = 0;
+ public static final int REASON_AUTOMATIC_OFF = 1;
+ public static final int REASON_MANUAL_ON = 2;
+ public static final int REASON_MANUAL_OFF = 3;
+ public static final int REASON_STICKY_RESTORE = 4;
+ public static final int REASON_INTERACTIVE_CHANGED = 5;
+ public static final int REASON_POLICY_CHANGED = 6;
+ public static final int REASON_PLUGGED_IN = 7;
+ public static final int REASON_SETTING_CHANGED = 8;
+
/**
* Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
*/
@@ -113,7 +123,8 @@
return; // No need to send it if not enabled.
}
// Don't send the broadcast, because we never did so in this case.
- mHandler.postStateChanged(/*sendBroadcast=*/ false);
+ mHandler.postStateChanged(/*sendBroadcast=*/ false,
+ REASON_INTERACTIVE_CHANGED);
break;
case Intent.ACTION_BATTERY_CHANGED:
synchronized (mLock) {
@@ -184,7 +195,7 @@
if (!isEnabled()) {
return; // No need to send it if not enabled.
}
- mHandler.postStateChanged(/*sendBroadcast=*/ true);
+ mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED);
}
private class MyHandler extends Handler {
@@ -199,9 +210,9 @@
super(looper);
}
- public void postStateChanged(boolean sendBroadcast) {
+ public void postStateChanged(boolean sendBroadcast, int reason) {
obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
- ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
+ ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
}
public void postSystemReady() {
@@ -212,7 +223,9 @@
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_STATE_CHANGED:
- handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
+ handleBatterySaverStateChanged(
+ msg.arg1 == ARG_SEND_BROADCAST,
+ msg.arg2);
break;
case MSG_SYSTEM_READY:
@@ -227,14 +240,14 @@
/**
* Called by {@link PowerManagerService} to update the battery saver stete.
*/
- public void enableBatterySaver(boolean enable) {
+ public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (mEnabled == enable) {
return;
}
mEnabled = enable;
- mHandler.postStateChanged(/*sendBroadcast=*/ true);
+ mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
}
}
@@ -275,7 +288,7 @@
* - When battery saver is on the interactive state changes.
* - When battery saver is on the battery saver policy changes.
*/
- void handleBatterySaverStateChanged(boolean sendBroadcast) {
+ void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
final LowPowerModeListener[] listeners;
final boolean enabled;
@@ -287,7 +300,8 @@
mPreviouslyEnabled ? 1 : 0, // Previously off or on.
mEnabled ? 1 : 0, // Now off or on.
isInteractive ? 1 : 0, // Device interactive state.
- mEnabled ? mBatterySaverPolicy.toEventLogString() : "");
+ mEnabled ? mBatterySaverPolicy.toEventLogString() : "",
+ reason);
mPreviouslyEnabled = mEnabled;
listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 2860521..b9f31b1 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -18,6 +18,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -27,6 +28,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.server.EventLogTags;
import com.android.server.power.BatterySaverPolicy;
import com.android.server.power.BatterySaverStateMachineProto;
@@ -95,6 +97,18 @@
@GuardedBy("mLock")
private boolean mBatterySaverSnoozing;
+ /**
+ * Last reason passed to {@link #enableBatterySaverLocked}.
+ */
+ @GuardedBy("mLock")
+ private int mLastChangedIntReason;
+
+ /**
+ * Last reason passed to {@link #enableBatterySaverLocked}.
+ */
+ @GuardedBy("mLock")
+ private String mLastChangedStrReason;
+
private final ContentObserver mSettingsObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -149,11 +163,25 @@
});
}
+ /**
+ * Run a {@link Runnable} on a background handler.
+ */
@VisibleForTesting
void runOnBgThread(Runnable r) {
BackgroundThread.getHandler().post(r);
}
+ /**
+ * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
+ * it'll be first removed before a new one is posted.
+ */
+ @VisibleForTesting
+ void runOnBgThreadLazy(Runnable r, int delayMillis) {
+ final Handler h = BackgroundThread.getHandler();
+ h.removeCallbacks(r);
+ h.postDelayed(r, delayMillis);
+ }
+
void refreshSettingsLocked() {
final ContentResolver cr = mContext.getContentResolver();
@@ -199,14 +227,23 @@
mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
+ if (thresholdChanged) {
+ // To avoid spamming the event log, we throttle logging here.
+ runOnBgThreadLazy(mThresholdChangeLogger, 2000);
+ }
+
if (enabledChanged) {
final String reason = batterySaverEnabled
? "Global.low_power changed to 1" : "Global.low_power changed to 0";
enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
- reason);
+ BatterySaverController.REASON_SETTING_CHANGED, reason);
}
}
+ private final Runnable mThresholdChangeLogger = () -> {
+ EventLogTags.writeBatterySaverSetting(mSettingBatterySaverTriggerThreshold);
+ };
+
/**
* {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
*
@@ -257,18 +294,26 @@
}
if (mIsPowered) {
updateSnoozingLocked(false, "Plugged in");
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Plugged in");
+ enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+ BatterySaverController.REASON_PLUGGED_IN,
+ "Plugged in");
} else if (mSettingBatterySaverEnabledSticky) {
// Re-enable BS.
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, "Sticky restore");
+ enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
+ BatterySaverController.REASON_STICKY_RESTORE,
+ "Sticky restore");
} else if (mIsBatteryLevelLow) {
if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, "Auto ON");
+ enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
+ BatterySaverController.REASON_AUTOMATIC_ON,
+ "Auto ON");
}
} else { // Battery not low
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Auto OFF");
+ enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+ BatterySaverController.REASON_AUTOMATIC_OFF,
+ "Auto OFF");
}
}
@@ -284,6 +329,8 @@
}
synchronized (mLock) {
enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
+ (enabled ? BatterySaverController.REASON_MANUAL_ON
+ : BatterySaverController.REASON_MANUAL_OFF),
(enabled ? "Manual ON" : "Manual OFF"));
}
}
@@ -292,10 +339,11 @@
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
*/
- private void enableBatterySaverLocked(boolean enable, boolean manual, String reason) {
+ private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
+ String strReason) {
if (DEBUG) {
Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
- + " reason=" + reason);
+ + " reason=" + strReason + "(" + intReason + ")");
}
final boolean wasEnabled = mBatterySaverController.isEnabled();
@@ -309,6 +357,8 @@
if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
return;
}
+ mLastChangedIntReason = intReason;
+ mLastChangedStrReason = strReason;
if (manual) {
if (enable) {
@@ -330,12 +380,12 @@
mSettingBatterySaverEnabledSticky = enable;
putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
}
- mBatterySaverController.enableBatterySaver(enable);
+ mBatterySaverController.enableBatterySaver(enable, intReason);
if (DEBUG) {
Slog.d(TAG, "Battery saver: Enabled=" + enable
+ " manual=" + manual
- + " reason=" + reason);
+ + " reason=" + strReason + "(" + intReason + ")");
}
}
@@ -365,6 +415,11 @@
pw.print(" Enabled=");
pw.println(mBatterySaverController.isEnabled());
+ pw.print(" mLastChangedIntReason=");
+ pw.println(mLastChangedIntReason);
+ pw.print(" mLastChangedStrReason=");
+ pw.println(mLastChangedStrReason);
+
pw.print(" mBootCompleted=");
pw.println(mBootCompleted);
pw.print(" mSettingsLoaded=");
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 2cd2ef1..c8baced 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -170,7 +170,7 @@
final int orientation = mTmpRect2.width() <= mTmpRect2.height()
? ORIENTATION_PORTRAIT
: ORIENTATION_LANDSCAPE;
- final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
+ final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
getContentWidth());
@@ -191,6 +191,39 @@
return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
}
+ /**
+ * Get the current docked side. Determined by its location of {@param bounds} within
+ * {@param displayRect} but if both are the same, it will try to dock to each side and determine
+ * if allowed in its respected {@param orientation}.
+ *
+ * @param bounds bounds of the docked task to get which side is docked
+ * @param displayRect bounds of the display that contains the docked task
+ * @param orientation the origination of device
+ * @return current docked side
+ */
+ int getDockSide(Rect bounds, Rect displayRect, int orientation) {
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // Portrait mode, docked either at the top or the bottom.
+ final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
+ if (diff > 0) {
+ return DOCKED_TOP;
+ } else if (diff < 0) {
+ return DOCKED_BOTTOM;
+ }
+ return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ // Landscape mode, docked either on the left or on the right.
+ final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
+ if (diff > 0) {
+ return DOCKED_LEFT;
+ } else if (diff < 0) {
+ return DOCKED_RIGHT;
+ }
+ return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
+ }
+ return DOCKED_INVALID;
+ }
+
void getHomeStackBoundsInDockedMode(Rect outBounds) {
final DisplayInfo di = mDisplayContent.getDisplayInfo();
mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
@@ -203,10 +236,20 @@
outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
di.logicalWidth, di.logicalHeight);
} else {
- // In landscape append the left position with the statusbar height to match the
+ // In landscape also inset the left/right side with the statusbar height to match the
// minimized size height in portrait mode.
- outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
- 0, di.logicalWidth, di.logicalHeight);
+ final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
+ int left = mTmpRect.left;
+ int right = di.logicalWidth - mTmpRect.right;
+ if (stack != null) {
+ if (stack.getDockSide() == DOCKED_LEFT) {
+ left += primaryTaskWidth;
+ } else if (stack.getDockSide() == DOCKED_RIGHT) {
+ right -= primaryTaskWidth;
+ }
+ }
+ outBounds.set(left, 0, right, di.logicalHeight);
}
}
@@ -420,21 +463,9 @@
* @return true if the side provided is valid
*/
boolean canPrimaryStackDockTo(int dockSide) {
- if (mService.mPolicy.isDockSideAllowed(dockSide)) {
- // Side is the same as original side
- if (dockSide == mOriginalDockedSide) {
- return true;
- }
- // Special rule that the top in portrait is always valid
- if (dockSide == DOCKED_TOP) {
- return true;
- }
- // Only if original docked side was top in portrait will allow left side for landscape
- if (dockSide == DOCKED_LEFT && mOriginalDockedSide == DOCKED_TOP) {
- return true;
- }
- }
- return false;
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
+ di.logicalHeight, di.rotation);
}
void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 018765d..891ee2e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1462,27 +1462,7 @@
}
dc.getBounds(mTmpRect);
final int orientation = dc.getConfiguration().orientation;
- return getDockSideUnchecked(bounds, mTmpRect, orientation);
- }
-
- static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // Portrait mode, docked either at the top or the bottom.
- if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
- return DOCKED_TOP;
- } else {
- return DOCKED_BOTTOM;
- }
- } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- // Landscape mode, docked either on the left or on the right.
- if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
- return DOCKED_LEFT;
- } else {
- return DOCKED_RIGHT;
- }
- } else {
- return DOCKED_INVALID;
- }
+ return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
}
boolean hasTaskForUser(int userId) {
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
index 64637f4..30665b5 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
@@ -28,12 +28,19 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
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 android.graphics.PixelFormat;
import android.platform.test.annotations.Presubmit;
@@ -194,4 +201,53 @@
PhoneWindowManager.updateLightNavigationBarLw(0, opaqueDarkNavBar,
opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
}
+
+ @Test
+ public void testIsDockSideAllowedDockTop() throws Exception {
+ // Docked top is always allowed
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedDockBottom() throws Exception {
+ // Cannot dock bottom
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarMovable() throws Exception {
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_LEFT,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_RIGHT,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_RIGHT,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_LEFT,
+ true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarNotMovable() throws Exception {
+ // Navigation bar is not movable such as tablets
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 1367f58..62fe6b2 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -144,6 +145,11 @@
void runOnBgThread(Runnable r) {
r.run();
}
+
+ @Override
+ void runOnBgThreadLazy(Runnable r, int delayMillis) {
+ r.run();
+ }
}
@Before
@@ -153,7 +159,7 @@
mMockBatterySaverController = mock(BatterySaverController.class);
doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
- .when(mMockBatterySaverController).enableBatterySaver(anyBoolean());
+ .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
when(mMockBatterySaverController.isEnabled())
.thenAnswer((inv) -> mDevice.batterySaverEnabled);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1c2d538..013c672 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -552,7 +552,8 @@
}
@Override
- public boolean isDockSideAllowed(int dockSide) {
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation) {
return false;
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index f164bcd..e213d79 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2964,12 +2964,30 @@
* @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;
+
}
/**