Merge "Don't use user-tagged Uris in slice callbacks"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 6975609..682885b 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -25,9 +25,12 @@
import android.support.test.runner.AndroidJUnit4;
import android.content.res.ColorStateList;
+import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
import org.junit.Before;
import org.junit.Rule;
@@ -285,4 +288,157 @@
.build();
}
}
+
+ @Test
+ public void testDraw_FixedText_NoStyled() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_RandomText_Styled() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_RandomText_NoStyled() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_RandomText_Styled_WithoutCache() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_RandomText_NoStyled_WithoutCache() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_MeasuredText_Styled() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final MeasuredText text = new MeasuredText.Builder(
+ generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_MeasuredText_NoStyled() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final MeasuredText text = new MeasuredText.Builder(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_MeasuredText_Styled_WithoutCache() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final MeasuredText text = new MeasuredText.Builder(
+ generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
+ @Test
+ public void testDraw_MeasuredText_NoStyled_WithoutCache() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final MeasuredText text = new MeasuredText.Builder(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+ final StaticLayout layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+ final DisplayListCanvas c = node.start(1200, 200);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ layout.draw(c);
+ }
+ }
+
}
diff --git a/api/current.txt b/api/current.txt
index bb4c383..52dbe9b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6474,6 +6474,7 @@
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean isPrintingEnabled();
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isResetPasswordTokenActive(android.content.ComponentName);
@@ -6543,6 +6544,7 @@
method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setPermittedCrossProfileNotificationListeners(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
+ method public void setPrintingEnabled(android.content.ComponentName, boolean);
method public void setProfileEnabled(android.content.ComponentName);
method public void setProfileName(android.content.ComponentName, java.lang.String);
method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
@@ -15843,6 +15845,7 @@
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4; // 0x4
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -21751,7 +21754,13 @@
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
+ field public static final int ENCODING_AAC_ELD = 15; // 0xf
+ field public static final int ENCODING_AAC_HE_V1 = 11; // 0xb
+ field public static final int ENCODING_AAC_HE_V2 = 12; // 0xc
+ field public static final int ENCODING_AAC_LC = 10; // 0xa
+ field public static final int ENCODING_AAC_XHE = 16; // 0x10
field public static final int ENCODING_AC3 = 5; // 0x5
+ field public static final int ENCODING_AC4 = 17; // 0x11
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
@@ -21759,6 +21768,7 @@
field public static final int ENCODING_E_AC3 = 6; // 0x6
field public static final int ENCODING_IEC61937 = 13; // 0xd
field public static final int ENCODING_INVALID = 0; // 0x0
+ field public static final int ENCODING_MP3 = 9; // 0x9
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
@@ -21801,6 +21811,7 @@
method public boolean isBluetoothScoOn();
method public boolean isMicrophoneMute();
method public boolean isMusicActive();
+ method public boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
method public boolean isSpeakerphoneOn();
method public boolean isStreamMute(int);
method public boolean isVolumeFixed();
@@ -22101,6 +22112,7 @@
method public int reloadStaticData();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+ method public void removeStreamEventCallback();
method public int setAuxEffectSendLevel(float);
method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
@@ -22114,6 +22126,7 @@
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method protected deprecated void setState(int);
method public deprecated int setStereoVolume(float, float);
+ method public void setStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
method public int setVolume(float);
method public void stop() throws java.lang.IllegalStateException;
method public int write(byte[], int, int);
@@ -22149,6 +22162,7 @@
method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
method public android.media.AudioTrack.Builder setPerformanceMode(int);
method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
@@ -22164,6 +22178,12 @@
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public static abstract class AudioTrack.StreamEventCallback {
+ method public void onStreamDataRequest(android.media.AudioTrack);
+ method public void onStreamPresentationEnd(android.media.AudioTrack);
+ method public void onTearDown(android.media.AudioTrack);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 66b6d99..dcea004 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -380,6 +380,7 @@
method public java.lang.CharSequence getDeviceOwnerOrganizationName();
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+ method public java.lang.CharSequence getPrintingDisabledReason();
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public int getUserProvisioningState();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b469de5..c5a58f2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -458,7 +459,8 @@
*
* @see Context#startActivity(Intent, Bundle)
*/
- public Activity startActivitySync(Intent intent, @Nullable Bundle options) {
+ @NonNull
+ public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) {
validateNotAppThread();
synchronized (mSync) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d465e0d..7fccda8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9210,10 +9210,13 @@
/**
* Allows/disallows printing.
*
+ * Called by a device owner or a profile owner.
+ * Device owner changes policy for all users. Profile owner can override it if present.
+ * Printing is enabled by default. If {@code FEATURE_PRINTING} is absent, the call is ignored.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled whether printing should be allowed or not.
* @throws SecurityException if {@code admin} is neither device, nor profile owner.
- * @hide
*/
public void setPrintingEnabled(@NonNull ComponentName admin, boolean enabled) {
try {
@@ -9224,10 +9227,12 @@
}
/**
- * Returns whether printing is enabled for current user.
+ * Returns whether printing is enabled for this user.
+ *
+ * Always {@code false} if {@code FEATURE_PRINTING} is absent.
+ * Otherwise, {@code true} by default.
*
* @return {@code true} iff printing is enabled.
- * @hide
*/
public boolean isPrintingEnabled() {
try {
@@ -9242,9 +9247,9 @@
*
* Used only by PrintService.
* @return Localized error message.
- * @throws SecurityException if caller is not system.
* @hide
*/
+ @SystemApi
public CharSequence getPrintingDisabledReason() {
try {
return mService.getPrintingDisabledReason();
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1201ef4..a9ed9a3 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2978,6 +2978,7 @@
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
+ * <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -2991,6 +2992,7 @@
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_3
+ * @see #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
*/
@PublicKey
public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 2294ec5..cc6e9a9 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1134,6 +1134,38 @@
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3;
+ /**
+ * <p>This camera device is backed by an external camera connected to this Android device.</p>
+ * <p>The device has capability identical to a LIMITED level device, with the following
+ * exceptions:</p>
+ * <ul>
+ * <li>The device may not report lens/sensor related information such as<ul>
+ * <li>{@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}</li>
+ * <li>{@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}</li>
+ * <li>{@link CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW android.sensor.rollingShutterSkew}</li>
+ * </ul>
+ * </li>
+ * <li>The device will report 0 for {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}</li>
+ * <li>The device has less guarantee on stable framerate, as the framerate partly depends
+ * on the external camera being used.</li>
+ * </ul>
+ *
+ * @see CaptureRequest#LENS_FOCAL_LENGTH
+ * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+ * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
+ * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+ * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
+ * @see CameraCharacteristics#SENSOR_ORIENTATION
+ * @see CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ */
+ public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4;
+
//
// Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
//
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b2cc18b..60ce42b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10375,6 +10375,15 @@
public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
/**
+ * Whether or not to enable Forced App Standby on small battery devices.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED
+ = "forced_app_standby_for_small_battery_enabled";
+
+ /**
* Whether or not Network Watchlist feature is enabled.
* Type: int (0 for false, 1 for true)
* Default: 0
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f409e5b..72afbb8 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -73,6 +73,7 @@
public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
+ public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index eefcb74..34544d3 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -18,8 +18,108 @@
#include <utils/String8.h>
+#include <map>
+
namespace android {
+static const std::map<int, std::string> sErrorCodesMap = {
+ // Primary Result Code List
+ {4, "SQLITE_ABORT"},
+ {23, "SQLITE_AUTH"},
+ {5, "SQLITE_BUSY"},
+ {14, "SQLITE_CANTOPEN"},
+ {19, "SQLITE_CONSTRAINT"},
+ {11, "SQLITE_CORRUPT"},
+ {101, "SQLITE_DONE"},
+ {16, "SQLITE_EMPTY"},
+ {1, "SQLITE_ERROR"},
+ {24, "SQLITE_FORMAT"},
+ {13, "SQLITE_FULL"},
+ {2, "SQLITE_INTERNAL"},
+ {9, "SQLITE_INTERRUPT"},
+ {10, "SQLITE_IOERR"},
+ {6, "SQLITE_LOCKED"},
+ {20, "SQLITE_MISMATCH"},
+ {21, "SQLITE_MISUSE"},
+ {22, "SQLITE_NOLFS"},
+ {7, "SQLITE_NOMEM"},
+ {26, "SQLITE_NOTADB"},
+ {12, "SQLITE_NOTFOUND"},
+ {27, "SQLITE_NOTICE"},
+ {0, "SQLITE_OK"},
+ {3, "SQLITE_PERM"},
+ {15, "SQLITE_PROTOCOL"},
+ {25, "SQLITE_RANGE"},
+ {8, "SQLITE_READONLY"},
+ {100, "SQLITE_ROW"},
+ {17, "SQLITE_SCHEMA"},
+ {18, "SQLITE_TOOBIG"},
+ {28, "SQLITE_WARNING"},
+ // Extended Result Code List
+ {516, "SQLITE_ABORT_ROLLBACK"},
+ {261, "SQLITE_BUSY_RECOVERY"},
+ {517, "SQLITE_BUSY_SNAPSHOT"},
+ {1038, "SQLITE_CANTOPEN_CONVPATH"},
+ {782, "SQLITE_CANTOPEN_FULLPATH"},
+ {526, "SQLITE_CANTOPEN_ISDIR"},
+ {270, "SQLITE_CANTOPEN_NOTEMPDIR"},
+ {275, "SQLITE_CONSTRAINT_CHECK"},
+ {531, "SQLITE_CONSTRAINT_COMMITHOOK"},
+ {787, "SQLITE_CONSTRAINT_FOREIGNKEY"},
+ {1043, "SQLITE_CONSTRAINT_FUNCTION"},
+ {1299, "SQLITE_CONSTRAINT_NOTNULL"},
+ {1555, "SQLITE_CONSTRAINT_PRIMARYKEY"},
+ {2579, "SQLITE_CONSTRAINT_ROWID"},
+ {1811, "SQLITE_CONSTRAINT_TRIGGER"},
+ {2067, "SQLITE_CONSTRAINT_UNIQUE"},
+ {2323, "SQLITE_CONSTRAINT_VTAB"},
+ {267, "SQLITE_CORRUPT_VTAB"},
+ {3338, "SQLITE_IOERR_ACCESS"},
+ {2826, "SQLITE_IOERR_BLOCKED"},
+ {3594, "SQLITE_IOERR_CHECKRESERVEDLOCK"},
+ {4106, "SQLITE_IOERR_CLOSE"},
+ {6666, "SQLITE_IOERR_CONVPATH"},
+ {2570, "SQLITE_IOERR_DELETE"},
+ {5898, "SQLITE_IOERR_DELETE_NOENT"},
+ {4362, "SQLITE_IOERR_DIR_CLOSE"},
+ {1290, "SQLITE_IOERR_DIR_FSYNC"},
+ {1802, "SQLITE_IOERR_FSTAT"},
+ {1034, "SQLITE_IOERR_FSYNC"},
+ {6410, "SQLITE_IOERR_GETTEMPPATH"},
+ {3850, "SQLITE_IOERR_LOCK"},
+ {6154, "SQLITE_IOERR_MMAP"},
+ {3082, "SQLITE_IOERR_NOMEM"},
+ {2314, "SQLITE_IOERR_RDLOCK"},
+ {266, "SQLITE_IOERR_READ"},
+ {5642, "SQLITE_IOERR_SEEK"},
+ {5130, "SQLITE_IOERR_SHMLOCK"},
+ {5386, "SQLITE_IOERR_SHMMAP"},
+ {4618, "SQLITE_IOERR_SHMOPEN"},
+ {4874, "SQLITE_IOERR_SHMSIZE"},
+ {522, "SQLITE_IOERR_SHORT_READ"},
+ {1546, "SQLITE_IOERR_TRUNCATE"},
+ {2058, "SQLITE_IOERR_UNLOCK"},
+ {778, "SQLITE_IOERR_WRITE"},
+ {262, "SQLITE_LOCKED_SHAREDCACHE"},
+ {539, "SQLITE_NOTICE_RECOVER_ROLLBACK"},
+ {283, "SQLITE_NOTICE_RECOVER_WAL"},
+ {256, "SQLITE_OK_LOAD_PERMANENTLY"},
+ {520, "SQLITE_READONLY_CANTLOCK"},
+ {1032, "SQLITE_READONLY_DBMOVED"},
+ {264, "SQLITE_READONLY_RECOVERY"},
+ {776, "SQLITE_READONLY_ROLLBACK"},
+ {284, "SQLITE_WARNING_AUTOINDEX"},
+};
+
+static std::string sqlite3_error_code_to_msg(int errcode) {
+ auto it = sErrorCodesMap.find(errcode);
+ if (it != sErrorCodesMap.end()) {
+ return std::to_string(errcode) + " " + it->second;
+ } else {
+ return std::to_string(errcode);
+ }
+}
+
/* throw a SQLiteException with a message appropriate for the error in handle */
void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
throw_sqlite3_exception(env, handle, NULL);
@@ -123,7 +223,8 @@
if (sqlite3Message) {
String8 fullMessage;
fullMessage.append(sqlite3Message);
- fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
+ const char* errcode_msg = sqlite3_error_code_to_msg(errcode).c_str();
+ fullMessage.appendFormat(" (code %s)", errcode_msg); // print extended error code
if (message) {
fullMessage.append(": ");
fullMessage.append(message);
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 51cefb9..c79f5bd 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -35,6 +35,7 @@
#define ENCODING_DOLBY_TRUEHD 14
#define ENCODING_AAC_ELD 15
#define ENCODING_AAC_XHE 16
+#define ENCODING_AC4 17
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -77,6 +78,8 @@
return AUDIO_FORMAT_AAC_ELD;
case ENCODING_AAC_XHE:
return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
+ case ENCODING_AC4:
+ return AUDIO_FORMAT_AC4;
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -125,6 +128,8 @@
// FIXME needs addition of AUDIO_FORMAT_AAC_XHE
//case AUDIO_FORMAT_AAC_XHE:
// return ENCODING_AAC_XHE;
+ case AUDIO_FORMAT_AC4:
+ return ENCODING_AC4;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 8753bf7..c9f7d52 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -41,4 +41,13 @@
// Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
+
+ // Whether device is a small battery device
+ optional bool is_small_battery_device = 6;
+
+ // Whether force app standby for small battery device setting is enabled
+ optional bool force_all_apps_standby_for_small_battery = 7;
+
+ // Whether device is charging
+ optional bool is_charging = 8;
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0c844c9..170ba42 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4821,4 +4821,7 @@
<!-- Text describing a permission request for one app to show another app's
slices [CHAR LIMIT=NONE] -->
<string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
+
+ <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
+ <string name="screenshot_edit">Edit</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 03a800d..9550657 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3227,5 +3227,8 @@
<java-symbol type="string" name="config_defaultAssistantAccessPackage" />
<java-symbol type="bool" name="config_supportBluetoothPersistedState" />
+
<java-symbol type="string" name="slices_permission_request" />
+
+ <java-symbol type="string" name="screenshot_edit" />
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec3a6ce..fa0ea5c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -213,6 +213,7 @@
Settings.Global.FANCY_IME_ANIMATIONS,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FORCED_APP_STANDBY_ENABLED,
+ Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
Settings.Global.FSTRIM_MANDATORY_INTERVAL,
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Settings.Global.GLOBAL_HTTP_PROXY_HOST,
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 46fe89a..b07d042 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -238,25 +238,13 @@
public static final int ENCODING_DTS = 7;
/** Audio data format: DTS HD compressed */
public static final int ENCODING_DTS_HD = 8;
- /** Audio data format: MP3 compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: MP3 compressed */
public static final int ENCODING_MP3 = 9;
- /** Audio data format: AAC LC compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: AAC LC compressed */
public static final int ENCODING_AAC_LC = 10;
- /** Audio data format: AAC HE V1 compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: AAC HE V1 compressed */
public static final int ENCODING_AAC_HE_V1 = 11;
- /** Audio data format: AAC HE V2 compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: AAC HE V2 compressed */
public static final int ENCODING_AAC_HE_V2 = 12;
/** Audio data format: compressed audio wrapped in PCM for HDMI
@@ -271,16 +259,12 @@
/** Audio data format: DOLBY TRUEHD compressed
**/
public static final int ENCODING_DOLBY_TRUEHD = 14;
- /** Audio data format: AAC ELD compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: AAC ELD compressed */
public static final int ENCODING_AAC_ELD = 15;
- /** Audio data format: AAC xHE compressed
- * @hide
- * TODO unhide and add to @Encoding (intentional white space
- * */
+ /** Audio data format: AAC xHE compressed */
public static final int ENCODING_AAC_XHE = 16;
+ /** Audio data format: AC-4 sync frame transport format */
+ public static final int ENCODING_AC4 = 17;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -317,6 +301,8 @@
return "ENCODING_AAC_ELD";
case ENCODING_AAC_XHE:
return "ENCODING_AAC_XHE";
+ case ENCODING_AC4:
+ return "ENCODING_AC4";
default :
return "invalid encoding " + enc;
}
@@ -535,6 +521,7 @@
case ENCODING_IEC61937:
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
+ case ENCODING_AC4:
return true;
default:
return false;
@@ -553,13 +540,13 @@
case ENCODING_DTS:
case ENCODING_DTS_HD:
case ENCODING_IEC61937:
- //TODO not true yet (intended white space
case ENCODING_MP3:
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
+ case ENCODING_AC4:
return true;
default:
return false;
@@ -586,6 +573,7 @@
case ENCODING_IEC61937: // wrapped in PCM but compressed
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
+ case ENCODING_AC4:
return false;
case ENCODING_INVALID:
default:
@@ -613,6 +601,7 @@
case ENCODING_AAC_HE_V2:
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
+ case ENCODING_AC4:
return false;
case ENCODING_INVALID:
default:
@@ -849,6 +838,7 @@
case ENCODING_AAC_HE_V2:
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
+ case ENCODING_AC4:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1056,7 +1046,13 @@
ENCODING_E_AC3,
ENCODING_DTS,
ENCODING_DTS_HD,
- ENCODING_IEC61937 }
+ ENCODING_IEC61937,
+ ENCODING_AAC_HE_V1,
+ ENCODING_AAC_HE_V2,
+ ENCODING_AAC_LC,
+ ENCODING_AAC_ELD,
+ ENCODING_AAC_XHE,
+ ENCODING_AC4 }
)
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4d5343c..2ac4063 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1331,15 +1331,13 @@
//====================================================================
// Offload query
/**
- * @hide
- * TODO unhide (intentional white space to attract attention:
* Returns whether offloaded playback of an audio format is supported on the device.
* Offloaded playback is where the decoding of an audio stream is not competing with other
* software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
* @param format the audio format (codec, sample rate, channels) being checked.
* @return true if the given audio format can be offloaded.
*/
- public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+ public boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
return AudioSystem.isOffloadSupported(format);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6add381..5928d03 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -755,8 +755,8 @@
* <code>MODE_STREAM</code> will be used.
* <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
* be generated.
+ * <br>Offload is false by default.
*/
- // TODO add that offload is false by default (intended white space
public static class Builder {
private AudioAttributes mAttributes;
private AudioFormat mFormat;
@@ -895,14 +895,11 @@
}
/**
- * @hide
- * TODO unhide (intentional whitespace
- * TODO should offload require POWER_SAVING?
* Sets whether this track will play through the offloaded audio path.
* When set to true, at build time, the audio format will be checked against
* {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
* used by this track is supported on the device's offload path (if any).
- * <br>Offload is only supported for media audio data, and therefore require that
+ * <br>Offload is only supported for media audio streams, and therefore requires that
* the usage be {@link AudioAttributes#USAGE_MEDIA}.
* @param offload true to require the offload path for playback.
* @return the same Builder instance.
@@ -962,7 +959,7 @@
throw new UnsupportedOperationException(
"Cannot create AudioTrack, offload requires USAGE_MEDIA");
}
- if (!AudioManager.isOffloadedPlaybackSupported(mFormat)) {
+ if (!AudioSystem.isOffloadSupported(mFormat)) {
throw new UnsupportedOperationException(
"Cannot create AudioTrack, offload format not supported");
}
@@ -2942,14 +2939,31 @@
}
/**
- * @hide
- * TODO unhide (intentional white space to attract attention:
* Abstract class to receive event notification about the stream playback.
+ * See {@link AudioTrack#setStreamEventCallback(Executor, StreamEventCallback)} to register
+ * the callback on the given {@link AudioTrack} instance.
*/
public abstract static class StreamEventCallback {
- // TODO rename if supported for non offload tracks
+ /** @hide */ // add hidden empty constructor so it doesn't show in SDK
+ public StreamEventCallback() { }
+ /**
+ * Called when an offloaded track is no longer valid and has been discarded by the system.
+ * An example of this happening is when an offloaded track has been paused too long, and
+ * gets invalidated by the system to prevent any other offload.
+ * @param track the {@link AudioTrack} on which the event happened
+ */
public void onTearDown(AudioTrack track) { }
+ /**
+ * Called when all the buffers of an offloaded track that were queued in the audio system
+ * (e.g. the combination of the Android audio framework and the device's audio hardware)
+ * have been played after {@link AudioTrack#stop()} has been called.
+ * @param track the {@link AudioTrack} on which the event happened
+ */
public void onStreamPresentationEnd(AudioTrack track) { }
+ /**
+ * Called when more audio data can be written without blocking on an offloaded track.
+ * @param track the {@link AudioTrack} on which the event happened
+ */
public void onStreamDataRequest(AudioTrack track) { }
}
@@ -2958,11 +2972,9 @@
private final Object mStreamEventCbLock = new Object();
/**
- * @hide
- * TODO unhide (intentional white space to attract attention:
- * Registers a callback for notification of stream events.
+ * Sets the callback for the notification of stream events.
* @param executor {@link Executor} to handle the callbacks
- * @param eventCallback the callback to receive the stream events
+ * @param eventCallback the callback to receive the stream event notifications
*/
public void setStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull StreamEventCallback eventCallback) {
@@ -2979,9 +2991,8 @@
}
/**
- * @hide
* Unregisters the callback for notification of stream events, previously set
- * by {@link #setStreamEventCallback(StreamEventCallback, Executor)}.
+ * by {@link #setStreamEventCallback(Executor, StreamEventCallback)}.
*/
public void removeStreamEventCallback() {
synchronized (mStreamEventCbLock) {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3c49b80..78477f7 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1380,7 +1380,8 @@
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
enableNativeRoutingCallbacksLocked(true);
mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : mEventHandler));
}
}
}
@@ -1401,36 +1402,6 @@
}
}
- /**
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeRoutingEventHandlerDelegate {
- private MediaRecorder mMediaRecorder;
- private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
- private Handler mHandler;
-
- NativeRoutingEventHandlerDelegate(final MediaRecorder mediaRecorder,
- final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
- mMediaRecorder = mediaRecorder;
- mOnRoutingChangedListener = listener;
- mHandler = handler != null ? handler : mEventHandler;
- }
-
- void notifyClient() {
- if (mHandler != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mOnRoutingChangedListener != null) {
- mOnRoutingChangedListener.onRoutingChanged(mMediaRecorder);
- }
- }
- });
- }
- }
- }
-
private native final boolean native_setInputDevice(int deviceId);
private native final int native_getRoutedDeviceId();
private native final void native_enableDeviceCallback(boolean enabled);
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
index c19fa08..24afebd 100644
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ b/packages/SystemUI/res/color/qs_background_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.87"
+ <item android:alpha="1"
android:color="?android:attr/colorBackgroundFloating"/>
</selector>
diff --git a/packages/SystemUI/res/drawable/ic_screenshot_edit.xml b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
new file mode 100644
index 0000000..d901292
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.81,9.94l-3.75,-3.75L3.0,17.25zM20.71,7.04c0.39,-0.3 0.39,-1.02 0.0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+ <path
+ android:pathData="M0 0h24v24H0z"
+ android:fillColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_bg_gradient.xml b/packages/SystemUI/res/drawable/qs_bg_gradient.xml
new file mode 100644
index 0000000..a1ad528
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_bg_gradient.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="270"
+ android:startColor="#ff000000"
+ android:endColor="#00000000"
+ android:type="linear" />
+</shape>
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index 59c0957..e52aa14 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -25,6 +25,6 @@
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
android:textColor="?android:attr/textColorPrimary"
android:gravity="center_vertical|start"
- android:paddingEnd="@dimen/battery_level_padding_start"
+ android:paddingStart="@dimen/battery_level_padding_start"
android:importantForAccessibility="no"
/>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 9ab8ac6..b3b6a0c 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -20,6 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:elevation="4dp"
android:orientation="vertical"
android:background="@drawable/qs_customizer_background"
android:gravity="center_horizontal">
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 1fd239b..0b9a7b2 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -23,7 +23,8 @@
android:clickable="true"
android:orientation="vertical"
android:paddingBottom="8dp"
- android:visibility="invisible">
+ android:visibility="invisible"
+ android:elevation="4dp" >
<include
android:id="@+id/qs_detail_header"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 3d09b74..9f6a946 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -21,6 +21,7 @@
android:id="@+id/qs_footer"
android:layout_width="match_parent"
android:layout_height="48dp"
+ android:elevation="4dp"
android:baselineAligned="false"
android:clickable="false"
android:clipChildren="false"
@@ -105,17 +106,6 @@
android:visibility="invisible"/>
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
- <com.android.systemui.statusbar.phone.ExpandableIndicator
- android:id="@+id/expand_indicator"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:clipToPadding="false"
- android:clickable="true"
- android:focusable="true"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/accessibility_quick_settings_expand"
- android:padding="14dp" />
</LinearLayout>
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 5541f3d..5bcb7fd 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -18,17 +18,46 @@
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/qs_background_primary"
- android:elevation="4dp"
android:clipToPadding="false"
- android:clipChildren="false">
+ android:clipChildren="false" >
+
+ <!-- Main QS background -->
+ <View
+ android:id="@+id/quick_settings_background"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:elevation="4dp"
+ android:background="@drawable/qs_background_primary" />
+
+ <!-- Black part behind the status bar -->
+ <View
+ android:id="@+id/quick_settings_status_bar_background"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_header_system_icons_area_height"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:background="#ff000000" />
+
+ <!-- Gradient view behind QS -->
+ <View
+ android:id="@+id/quick_settings_gradient_view"
+ android:layout_width="match_parent"
+ android:layout_height="126dp"
+ android:layout_marginTop="@dimen/qs_header_system_icons_area_height"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:background="@drawable/qs_bg_gradient" />
+
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
- android:layout_marginTop="28dp"
+ android:layout_marginTop="@dimen/qs_header_system_icons_area_height"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="48dp" />
+ android:layout_marginBottom="48dp"
+ android:elevation="4dp"
+ />
+
<include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
new file mode 100644
index 0000000..e0f0ed9
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/quick_qs_status_icons"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"
+ android:layout_marginBottom="22dp"
+ android:layout_below="@id/quick_status_bar_system_icons"
+ >
+
+</View>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index e8b418c..dacc3f9 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -28,23 +28,21 @@
android:clipToPadding="false"
android:paddingTop="0dp"
android:paddingEnd="0dp"
- android:paddingStart="0dp">
+ android:paddingStart="0dp"
+ android:elevation="4dp" >
<include layout="@layout/quick_status_bar_header_system_icons" />
+ <include layout="@layout/quick_qs_status_icons" />
<com.android.systemui.qs.QuickQSPanel
android:id="@+id/quick_qs_panel"
android:layout_width="match_parent"
android:layout_height="48dp"
- android:layout_alignParentEnd="true"
- android:layout_marginTop="31dp"
- android:layout_alignParentTop="true"
+ android:layout_below="@id/quick_qs_status_icons"
android:accessibilityTraversalAfter="@+id/date_time_group"
android:accessibilityTraversalBefore="@id/expand_indicator"
android:clipChildren="false"
android:clipToPadding="false"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
android:focusable="true"
android:importantForAccessibility="yes" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 739a255..bfe1b62 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -17,6 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/quick_status_bar_system_icons"
android:layout_width="match_parent"
android:layout_height="@dimen/qs_header_system_icons_area_height"
android:layout_alignParentEnd="true"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 17b38cb..8c0b9ba 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -54,30 +54,47 @@
android:layout_height="match_parent"
android:layout="@layout/operator_name" />
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_width="wrap_content"
+ <LinearLayout
android:layout_height="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
- android:gravity="center_vertical|start"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ >
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+ android:gravity="center_vertical|start"
+ />
+
+ <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
+ PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
+ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+ android:id="@+id/notification_icon_area"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="horizontal" />
+
+ </LinearLayout>
+
+ <!-- Space should cover the notch (if it exists) and let other views lay out around it -->
+ <android.widget.Space
+ android:id="@+id/cutout_space_view"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal|center_vertical"
/>
- <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
- PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/notification_icon_area"
- android:layout_width="0dip"
+ <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
+ android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:orientation="horizontal" />
-
- <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
android:orientation="horizontal"
+ android:gravity="center_vertical|end"
>
<include layout="@layout/system_icons" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index c5e5ee1..bef0830 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -43,8 +43,6 @@
android:layout_width="@dimen/qs_panel_width"
android:layout_height="match_parent"
android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:layout_marginStart="@dimen/notification_side_paddings"
- android:layout_marginEnd="@dimen/notification_side_paddings"
android:clipToPadding="false"
android:clipChildren="false"
systemui:viewType="com.android.systemui.plugins.qs.QS" />
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index bfa92ad..1fafb2f 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -16,12 +16,13 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/system_icons"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
- <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
+ <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
+ android:layout_width="0dp"
+ android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0134086..4e17c71 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -215,7 +215,7 @@
<dimen name="close_handle_underlap">32dp</dimen>
<!-- Height of the status bar header bar -->
- <dimen name="status_bar_header_height">124dp</dimen>
+ <dimen name="status_bar_header_height">178dp</dimen>
<!-- Height of the status bar header bar in the car setting. -->
<dimen name="car_status_bar_header_height">128dp</dimen>
@@ -223,8 +223,9 @@
<!-- The bottom padding of the status bar header. -->
<dimen name="status_bar_header_padding_bottom">48dp</dimen>
- <!-- The height of the container that holds the system icons in the quick settings header. -->
- <dimen name="qs_header_system_icons_area_height">40dp</dimen>
+ <!-- The height of the container that holds the battery and time in the quick settings header.
+ -->
+ <dimen name="qs_header_system_icons_area_height">48dp</dimen>
<!-- The height of the container that holds the system icons in the quick settings header in the
car setting. -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index fed97c5..edda613 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -93,5 +93,8 @@
<item type="id" name="action_snooze_long"/>
<item type="id" name="action_snooze_longer"/>
<item type="id" name="action_snooze_assistant_suggestion_1"/>
+
+ <!-- For StatusBarIconContainer to tag its icon views -->
+ <item type="id" name="status_bar_view_state_tag" />
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2fe66a1..8666b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -224,7 +224,6 @@
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
updatePercentText();
addView(mBatteryPercentView,
- 0,
new ViewGroup.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7f0acc2..7320b86 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -45,8 +45,9 @@
protected float mQsExpansion;
private QSCustomizer mQSCustomizer;
private View mQSFooter;
- private float mFullElevation;
+ private View mBackground;
private float mRadius;
+ private int mSideMargins;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -60,12 +61,14 @@
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
mQSFooter = findViewById(R.id.qs_footer);
- mFullElevation = mQSPanel.getElevation();
+ mBackground = findViewById(R.id.quick_settings_background);
mRadius = getResources().getDimensionPixelSize(
Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
setClickable(true);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+ setMargins();
}
@Override
@@ -131,6 +134,8 @@
mQSDetail.setBottom(getTop() + height);
// Pin QS Footer to the bottom of the panel.
mQSFooter.setTranslationY(height - mQSFooter.getHeight());
+ mBackground.setTop(mQSPanel.getTop());
+ mBackground.setBottom(height);
ExpandableOutlineView.getRoundedRectPath(0, 0, getWidth(), height, mRadius,
mRadius,
@@ -148,4 +153,19 @@
mQsExpansion = expansion;
updateExpansion();
}
+
+ private void setMargins() {
+ setMargins(mQSDetail);
+ setMargins(mBackground);
+ setMargins(mQSFooter);
+ setMargins(mQSPanel);
+ setMargins(mHeader);
+ setMargins(mQSCustomizer);
+ }
+
+ private void setMargins(View view) {
+ FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.rightMargin = mSideMargins;
+ lp.leftMargin = mSideMargins;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 927a49c..92475da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -61,18 +61,16 @@
public class QSFooterImpl extends FrameLayout implements QSFooter,
OnClickListener, OnUserInfoChangedListener, EmergencyListener,
SignalCallback, CommandQueue.Callbacks {
- private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
-
private ActivityStarter mActivityStarter;
private UserInfoController mUserInfoController;
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
+ private View mCarrierText;
private boolean mQsDisabled;
private QSPanel mQsPanel;
private boolean mExpanded;
- protected ExpandableIndicator mExpandIndicator;
private boolean mListening;
@@ -100,18 +98,18 @@
Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
mQsPanel.showEdit(view)));
- mExpandIndicator = findViewById(R.id.expand_indicator);
mSettingsButton = findViewById(R.id.settings_button);
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
+ mCarrierText = findViewById(R.id.qs_carrier_text);
+
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
- ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
updateResources();
@@ -162,6 +160,8 @@
return new TouchAnimator.Builder()
.addFloat(mEdit, "alpha", 0, 1)
.addFloat(mMultiUserSwitch, "alpha", 0, 1)
+ .addFloat(mCarrierText, "alpha", 0, 1)
+ .addFloat(mSettingsButton, "alpha", 0, 1)
.build();
}
@@ -185,8 +185,6 @@
if (mSettingsAlpha != null) {
mSettingsAlpha.setPosition(headerExpansionFraction);
}
-
- mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
}
@Override
@@ -237,8 +235,6 @@
mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
- mExpandIndicator.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
-
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 398592a..e6fd2f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -38,6 +38,7 @@
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks {
@@ -69,15 +70,13 @@
updateResources();
- // Set the light/dark theming on the header status UI to match the current theme.
+ // Set light text on the header icons because they will always be on a black background
int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
- float intensity = colorForeground == Color.WHITE ? 0 : 1;
Rect tintArea = new Rect(0, 0, 0, 0);
-
- applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
- applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
+ applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
BatteryMeterView battery = findViewById(R.id.battery);
+ battery.setFillColor(Color.WHITE);
battery.setForceShowPercent(true);
mActivityStarter = Dependency.get(ActivityStarter.class);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 6db46b5..675aa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -293,12 +293,13 @@
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
- // Create a share action for the notification. Note, we proxy the call to ShareReceiver
- // because RemoteViews currently forces an activity options on the PendingIntent being
- // launched, and since we don't want to trigger the share sheet in this case, we will
- // start the chooser activitiy directly in ShareReceiver.
+ // Create a share action for the notification. Note, we proxy the call to
+ // ScreenshotActionReceiver because RemoteViews currently forces an activity options
+ // on the PendingIntent being launched, and since we don't want to trigger the share
+ // sheet in this case, we start the chooser activity directly in
+ // ScreenshotActionReceiver.
PendingIntent shareAction = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.ShareReceiver.class)
+ new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
.putExtra(SHARING_INTENT, sharingIntent),
PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
@@ -306,15 +307,19 @@
r.getString(com.android.internal.R.string.share), shareAction);
mNotificationBuilder.addAction(shareActionBuilder.build());
- // Create a delete action for the notification
- PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
- .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
- Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
- R.drawable.ic_screenshot_delete,
- r.getString(com.android.internal.R.string.delete), deleteAction);
- mNotificationBuilder.addAction(deleteActionBuilder.build());
+ Intent editIntent = new Intent(Intent.ACTION_EDIT);
+ editIntent.setType("image/png");
+ editIntent.putExtra(Intent.EXTRA_STREAM, uri);
+
+ // Create a edit action for the notification the same way.
+ PendingIntent editAction = PendingIntent.getBroadcast(context, 1,
+ new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
+ .putExtra(SHARING_INTENT, editIntent),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
+ R.drawable.ic_screenshot_edit,
+ r.getString(com.android.internal.R.string.screenshot_edit), editAction);
+ mNotificationBuilder.addAction(editActionBuilder.build());
mParams.imageUri = uri;
mParams.image = null;
@@ -879,9 +884,9 @@
}
/**
- * Receiver to proxy the share intent.
+ * Receiver to proxy the share or edit intent.
*/
- public static class ShareReceiver extends BroadcastReceiver {
+ public static class ScreenshotActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
@@ -903,7 +908,7 @@
}
/**
- * Removes the notification for a screenshot after a share target is chosen.
+ * Removes the notification for a screenshot after a share or edit target is chosen.
*/
public static class TargetChosenReceiver extends BroadcastReceiver {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 970d1de..e8b28f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,26 +16,34 @@
package com.android.systemui.statusbar.phone;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.EventLog;
+import android.view.DisplayCutout;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.BatteryMeterView;
-import com.android.systemui.DejankUtils;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.util.leak.RotationUtils;
public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
+ private static final int NO_VALUE = Integer.MIN_VALUE;
StatusBar mBar;
@@ -53,6 +61,10 @@
}
};
private DarkReceiver mBattery;
+ private int mLastOrientation;
+ private View mCutoutSpace;
+ @Nullable
+ private DisplayCutout mDisplayCutout;
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -76,6 +88,7 @@
public void onFinishInflate() {
mBarTransitions.init();
mBattery = findViewById(R.id.battery);
+ mCutoutSpace = findViewById(R.id.cutout_space_view);
}
@Override
@@ -83,12 +96,51 @@
super.onAttachedToWindow();
// Always have Battery meters in the status bar observe the dark/light modes.
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
+ if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
+ postUpdateLayoutForCutout();
+ }
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
+ mDisplayCutout = null;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ // May trigger cutout space layout-ing
+ if (updateOrientationAndCutout(newConfig.orientation)) {
+ postUpdateLayoutForCutout();
+ }
+ }
+
+ /**
+ *
+ * @param newOrientation may pass NO_VALUE for no change
+ * @return boolean indicating if we need to update the cutout location / margins
+ */
+ private boolean updateOrientationAndCutout(int newOrientation) {
+ boolean changed = false;
+ if (newOrientation != NO_VALUE) {
+ if (mLastOrientation != newOrientation) {
+ changed = true;
+ mLastOrientation = newOrientation;
+ }
+ }
+
+ if (mDisplayCutout == null) {
+ DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
+ if (cutout != null) {
+ changed = true;
+ mDisplayCutout = cutout;
+ }
+ }
+
+ return changed;
}
@Override
@@ -214,4 +266,75 @@
R.dimen.status_bar_height);
setLayoutParams(layoutParams);
}
+
+ private void updateLayoutForCutout() {
+ updateCutoutLocation();
+ updateSafeInsets();
+ }
+
+ private void postUpdateLayoutForCutout() {
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ updateLayoutForCutout();
+ }
+ };
+ // Let the cutout emulation draw first
+ postDelayed(r, 0);
+ }
+
+ private void updateCutoutLocation() {
+ if (mDisplayCutout == null || mDisplayCutout.isEmpty()
+ || mLastOrientation != ORIENTATION_PORTRAIT) {
+ mCutoutSpace.setVisibility(View.GONE);
+ return;
+ }
+
+ mCutoutSpace.setVisibility(View.VISIBLE);
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
+ lp.width = mDisplayCutout.getBoundingRect().width();
+ lp.height = mDisplayCutout.getBoundingRect().height();
+ }
+
+ private void updateSafeInsets() {
+ // Depending on our rotation, we may have to work around a cutout in the middle of the view,
+ // or letterboxing from the right or left sides.
+
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+ lp.leftMargin = 0;
+ lp.rightMargin = 0;
+ return;
+ }
+
+ int leftMargin = 0;
+ int rightMargin = 0;
+ switch (RotationUtils.getRotation(getContext())) {
+ /*
+ * Landscape: <-|
+ * Seascape: |->
+ */
+ case RotationUtils.ROTATION_LANDSCAPE:
+ leftMargin = getDisplayCutoutHeight();
+ break;
+ case RotationUtils.ROTATION_SEASCAPE:
+ rightMargin = getDisplayCutoutHeight();
+ break;
+ default:
+ break;
+ }
+
+ lp.leftMargin = leftMargin;
+ lp.rightMargin = rightMargin;
+ }
+
+ //TODO: Find a better way
+ private int getDisplayCutoutHeight() {
+ if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+ return 0;
+ }
+
+ Rect r = mDisplayCutout.getBoundingRect();
+ return r.bottom - r.top;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index bcda60e..07610ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -62,7 +62,7 @@
}
/**
- * Version of ViewGroup that observers state from the DarkIconDispatcher.
+ * Version of ViewGroup that observes state from the DarkIconDispatcher.
*/
public static class DarkIconManager extends IconManager {
private final DarkIconDispatcher mDarkIconDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
new file mode 100644
index 0000000..1897171
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A container for Status bar system icons. Limits the number of system icons and handles overflow
+ * similar to NotificationIconController. Can be used to layout nested StatusIconContainers
+ *
+ * Children are expected to be of type StatusBarIconView.
+ */
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+
+import android.view.View;
+import com.android.keyguard.AlphaOptimizedLinearLayout;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.stack.ViewState;
+
+public class StatusIconContainer extends AlphaOptimizedLinearLayout {
+
+ private static final String TAG = "StatusIconContainer";
+ private static final int MAX_ICONS = 5;
+ private static final int MAX_DOTS = 3;
+
+ public StatusIconContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ float midY = getHeight() / 2.0f;
+
+ // Layout all child views so that we can move them around later
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ int width = child.getMeasuredWidth();
+ int height = child.getMeasuredHeight();
+ int top = (int) (midY - height / 2.0f);
+ child.layout(0, top, width, top + height);
+ }
+
+ resetViewStates();
+ calculateIconTranslations();
+ applyIconStates();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ final int count = getChildCount();
+ // Measure all children so that they report the correct width
+ for (int i = 0; i < count; i++) {
+ measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ @Override
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+ ViewState vs = new ViewState();
+ child.setTag(R.id.status_bar_view_state_tag, vs);
+ }
+
+ @Override
+ public void onViewRemoved(View child) {
+ super.onViewRemoved(child);
+ child.setTag(R.id.status_bar_view_state_tag, null);
+ }
+
+ /**
+ * Layout is happening from end -> start
+ */
+ private void calculateIconTranslations() {
+ float translationX = getWidth();
+ float contentStart = getPaddingStart();
+ int childCount = getChildCount();
+ // Underflow === don't show content until that index
+ int firstUnderflowIndex = -1;
+ android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
+
+ //TODO: Dots
+ for (int i = childCount - 1; i >= 0; i--) {
+ View child = getChildAt(i);
+ if (!(child instanceof StatusBarIconView)) {
+ continue;
+ }
+
+ ViewState childState = getViewStateFromChild(child);
+ if (childState == null ) {
+ continue;
+ }
+
+ // Rely on StatusBarIcon for truth about visibility
+ if (!((StatusBarIconView) child).getStatusBarIcon().visible) {
+ childState.hidden = true;
+ continue;
+ }
+
+ childState.xTranslation = translationX - child.getWidth();
+
+ if (childState.xTranslation < contentStart) {
+ if (firstUnderflowIndex == -1) {
+ firstUnderflowIndex = i;
+ }
+ }
+
+ translationX -= child.getWidth();
+ }
+
+ if (firstUnderflowIndex != -1) {
+ for (int i = 0; i <= firstUnderflowIndex; i++) {
+ View child = getChildAt(i);
+ ViewState vs = getViewStateFromChild(child);
+ if (vs != null) {
+ vs.hidden = true;
+ }
+ }
+ }
+ }
+
+ private void applyIconStates() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ ViewState vs = getViewStateFromChild(child);
+ if (vs != null) {
+ vs.applyToView(child);
+ }
+ }
+ }
+
+ private void resetViewStates() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ ViewState vs = getViewStateFromChild(child);
+ if (vs == null) {
+ continue;
+ }
+
+ vs.initFrom(child);
+ vs.alpha = 1.0f;
+ if (child instanceof StatusBarIconView) {
+ vs.hidden = !((StatusBarIconView)child).getStatusBarIcon().visible;
+ } else {
+ vs.hidden = false;
+ }
+ }
+ }
+
+ private static @Nullable ViewState getViewStateFromChild(View child) {
+ return (ViewState) child.getTag(R.id.status_bar_view_state_tag);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 66524cc..2edcd01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -74,6 +74,8 @@
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
+ assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
+ .getVisibility());
}
@Test
@@ -87,11 +89,15 @@
assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
+ assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.clock)
+ .getVisibility());
fragment.disable(0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
+ assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
+ .getVisibility());
}
@Test
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index a538bde..de113a6 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -26,6 +26,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -89,6 +91,9 @@
private final MyHandler mHandler;
+ @VisibleForTesting
+ FeatureFlagsObserver mFlagsObserver;
+
/**
* Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
*/
@@ -113,14 +118,36 @@
@GuardedBy("mLock")
boolean mStarted;
+ /**
+ * Only used for small battery use-case.
+ */
@GuardedBy("mLock")
- boolean mForceAllAppsStandby; // True if device is in extreme battery saver mode
+ boolean mIsPluggedIn;
@GuardedBy("mLock")
- boolean mForcedAppStandbyEnabled; // True if the forced app standby feature is enabled
+ boolean mBatterySaverEnabled;
- private class FeatureFlagObserver extends ContentObserver {
- FeatureFlagObserver() {
+ /**
+ * True if the forced app standby is currently enabled
+ */
+ @GuardedBy("mLock")
+ boolean mForceAllAppsStandby;
+
+ /**
+ * True if the forced app standby for small battery devices feature is enabled in settings
+ */
+ @GuardedBy("mLock")
+ boolean mForceAllAppStandbyForSmallBattery;
+
+ /**
+ * True if the forced app standby feature is enabled in settings
+ */
+ @GuardedBy("mLock")
+ boolean mForcedAppStandbyEnabled;
+
+ @VisibleForTesting
+ class FeatureFlagsObserver extends ContentObserver {
+ FeatureFlagsObserver() {
super(null);
}
@@ -128,6 +155,9 @@
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
false, this);
+
+ mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
}
boolean isForcedAppStandbyEnabled() {
@@ -135,20 +165,43 @@
Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
}
+ boolean isForcedAppStandbyForSmallBatteryEnabled() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
+ }
+
@Override
- public void onChange(boolean selfChange) {
- final boolean enabled = isForcedAppStandbyEnabled();
- synchronized (mLock) {
- if (mForcedAppStandbyEnabled == enabled) {
- return;
+ public void onChange(boolean selfChange, Uri uri) {
+ if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
+ final boolean enabled = isForcedAppStandbyEnabled();
+ synchronized (mLock) {
+ if (mForcedAppStandbyEnabled == enabled) {
+ return;
+ }
+ mForcedAppStandbyEnabled = enabled;
+ if (DEBUG) {
+ Slog.d(TAG,"Forced app standby feature flag changed: "
+ + mForcedAppStandbyEnabled);
+ }
}
- mForcedAppStandbyEnabled = enabled;
- if (DEBUG) {
- Slog.d(TAG,
- "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
+ mHandler.notifyForcedAppStandbyFeatureFlagChanged();
+ } else if (Settings.Global.getUriFor(
+ Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
+ final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
+ synchronized (mLock) {
+ if (mForceAllAppStandbyForSmallBattery == enabled) {
+ return;
+ }
+ mForceAllAppStandbyForSmallBattery = enabled;
+ if (DEBUG) {
+ Slog.d(TAG, "Forced app standby for small battery feature flag changed: "
+ + mForceAllAppStandbyForSmallBattery);
+ }
+ updateForceAllAppStandbyState();
}
+ } else {
+ Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
}
- mHandler.notifyFeatureFlagChanged();
}
}
@@ -289,9 +342,11 @@
mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
- final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
- flagObserver.register();
- mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
+ mFlagsObserver = new FeatureFlagsObserver();
+ mFlagsObserver.register();
+ mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
+ mForceAllAppStandbyForSmallBattery =
+ mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
try {
mIActivityManager.registerUidObserver(new UidObserver(),
@@ -306,16 +361,24 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
mContext.registerReceiver(new MyReceiver(), filter);
refreshForcedAppStandbyUidPackagesLocked();
mPowerManagerInternal.registerLowPowerModeObserver(
ServiceType.FORCE_ALL_APPS_STANDBY,
- (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
+ (state) -> {
+ synchronized (mLock) {
+ mBatterySaverEnabled = state.batterySaverEnabled;
+ updateForceAllAppStandbyState();
+ }
+ });
- updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
- ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
+ mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
+ ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
+
+ updateForceAllAppStandbyState();
}
}
@@ -340,6 +403,11 @@
return LocalServices.getService(PowerManagerInternal.class);
}
+ @VisibleForTesting
+ boolean isSmallBatteryDevice() {
+ return ActivityManager.isSmallBatteryDevice();
+ }
+
/**
* Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
*/
@@ -369,18 +437,26 @@
}
}
+ private void updateForceAllAppStandbyState() {
+ synchronized (mLock) {
+ if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
+ toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
+ } else {
+ toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
+ }
+ }
+ }
+
/**
* Update {@link #mForceAllAppsStandby} and notifies the listeners.
*/
- void updateForceAllAppsStandby(boolean enable) {
- synchronized (mLock) {
- if (enable == mForceAllAppsStandby) {
- return;
- }
- mForceAllAppsStandby = enable;
-
- mHandler.notifyForceAllAppsStandbyChanged();
+ private void toggleForceAllAppsStandbyLocked(boolean enable) {
+ if (enable == mForceAllAppsStandby) {
+ return;
}
+ mForceAllAppsStandby = enable;
+
+ mHandler.notifyForceAllAppsStandbyChanged();
}
private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
@@ -515,6 +591,11 @@
if (userId > 0) {
mHandler.doUserRemoved(userId);
}
+ } else if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+ synchronized (mLock) {
+ mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
+ }
+ updateForceAllAppStandbyState();
}
}
}
@@ -533,7 +614,7 @@
private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
private static final int MSG_FORCE_ALL_CHANGED = 6;
private static final int MSG_USER_REMOVED = 7;
- private static final int MSG_FEATURE_FLAG_CHANGED = 8;
+ private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
public MyHandler(Looper looper) {
super(looper);
@@ -563,8 +644,8 @@
obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
}
- public void notifyFeatureFlagChanged() {
- obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
+ public void notifyForcedAppStandbyFeatureFlagChanged() {
+ obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
}
public void doUserRemoved(int userId) {
@@ -618,7 +699,7 @@
l.onForceAllAppsStandbyChanged(sender);
}
return;
- case MSG_FEATURE_FLAG_CHANGED:
+ case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
// Feature flag for forced app standby changed.
final boolean unblockAlarms;
synchronized (mLock) {
@@ -845,6 +926,18 @@
pw.println(isForceAllAppsStandbyEnabled());
pw.print(indent);
+ pw.print("Small Battery Device: ");
+ pw.println(isSmallBatteryDevice());
+
+ pw.print(indent);
+ pw.print("Force all apps standby for small battery device: ");
+ pw.println(mForceAllAppStandbyForSmallBattery);
+
+ pw.print(indent);
+ pw.print("Plugged In: ");
+ pw.println(mIsPluggedIn);
+
+ pw.print(indent);
pw.print("Foreground uids: [");
String sep = "";
@@ -883,6 +976,11 @@
final long token = proto.start(fieldId);
proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
+ proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
+ isSmallBatteryDevice());
+ proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
+ mForceAllAppStandbyForSmallBattery);
+ proto.write(ForceAppStandbyTrackerProto.IS_CHARGING, mIsPluggedIn);
for (int i = 0; i < mForegroundUids.size(); i++) {
if (mForegroundUids.valueAt(i)) {
diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
index 80f8e51..833def3 100644
--- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
+++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
@@ -26,4 +26,7 @@
/** Retrieves handle to a lockscreen credential to be used for Factory Reset Protection. */
byte[] getFrpCredentialHandle();
+
+ /** Update the OEM unlock enabled bit, bypassing user restriction checks. */
+ void forceOemUnlockEnabled(boolean enabled);
}
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index c32a2d1..4298140 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -668,5 +668,13 @@
IoUtils.closeQuietly(inputStream);
}
}
+
+ @Override
+ public void forceOemUnlockEnabled(boolean enabled) {
+ synchronized (mLock) {
+ doSetOemUnlockEnabledLocked(enabled);
+ computeAndWriteDigestLocked();
+ }
+ }
};
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 8910274..26d65bc 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -745,7 +745,7 @@
mContext.getContentResolver(),
Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
0,
- UserHandle.USER_CURRENT) != 0;
+ mService.mUserController.getCurrentUserId()) != 0;
final boolean crashSilenced = mAppsNotReportingCrashes != null &&
mAppsNotReportingCrashes.contains(proc.info.packageName);
if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index fbf11fc..7387ad4 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -161,7 +161,7 @@
public boolean containsDomain(String domain) {
final CrcShaDigests domainDigests = mDomainDigests;
if (domainDigests == null) {
- Slog.wtf(TAG, "domainDigests should not be null");
+ // mDomainDigests is not initialized
return false;
}
// First it does a quick CRC32 check.
@@ -177,7 +177,7 @@
public boolean containsIp(String ip) {
final CrcShaDigests ipDigests = mIpDigests;
if (ipDigests == null) {
- Slog.wtf(TAG, "ipDigests should not be null");
+ // mIpDigests is not initialized
return false;
}
// First it does a quick CRC32 check.
@@ -234,12 +234,20 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Domain CRC32 digest list:");
- mDomainDigests.crc32Digests.dump(fd, pw, args);
+ if (mDomainDigests != null) {
+ mDomainDigests.crc32Digests.dump(fd, pw, args);
+ }
pw.println("Domain SHA256 digest list:");
- mDomainDigests.sha256Digests.dump(fd, pw, args);
+ if (mDomainDigests != null) {
+ mDomainDigests.sha256Digests.dump(fd, pw, args);
+ }
pw.println("Ip CRC32 digest list:");
- mIpDigests.crc32Digests.dump(fd, pw, args);
+ if (mIpDigests != null) {
+ mIpDigests.crc32Digests.dump(fd, pw, args);
+ }
pw.println("Ip SHA256 digest list:");
- mIpDigests.sha256Digests.dump(fd, pw, args);
+ if (mIpDigests != null) {
+ mIpDigests.sha256Digests.dump(fd, pw, args);
+ }
}
}
diff --git a/services/core/java/com/android/server/oemlock/OemLockService.java b/services/core/java/com/android/server/oemlock/OemLockService.java
index 2a2ff06..a6200bf 100644
--- a/services/core/java/com/android/server/oemlock/OemLockService.java
+++ b/services/core/java/com/android/server/oemlock/OemLockService.java
@@ -31,10 +31,10 @@
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.service.oemlock.IOemLockService;
-import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Slog;
import com.android.server.LocalServices;
+import com.android.server.PersistentDataBlockManagerInternal;
import com.android.server.SystemService;
import com.android.server.pm.UserRestrictionsUtils;
@@ -217,13 +217,12 @@
* is used to erase FRP information on a unlockable device.
*/
private void setPersistentDataBlockOemUnlockAllowedBit(boolean allowed) {
- final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
- mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+ final PersistentDataBlockManagerInternal pdbmi
+ = LocalServices.getService(PersistentDataBlockManagerInternal.class);
// if mOemLock is PersistentDataBlockLock, then the bit should have already been set
- if (pdbm != null && !(mOemLock instanceof PersistentDataBlockLock)
- && pdbm.getOemUnlockEnabled() != allowed) {
+ if (pdbmi != null && !(mOemLock instanceof PersistentDataBlockLock)) {
Slog.i(TAG, "Update OEM Unlock bit in pst partition to " + allowed);
- pdbm.setOemUnlockEnabled(allowed);
+ pdbmi.forceOemUnlockEnabled(allowed);
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b474c62..ce3f512 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -463,10 +463,14 @@
mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
}
- // Update the client visibility if we are not running an animation. Otherwise, we'll
- // update client visibility state in onAnimationFinished.
- if (!visible && !delayed) {
- setClientHidden(true);
+ // If we're becoming visible, immediately change client visibility as well although it
+ // usually gets changed in AppWindowContainerController.setVisibility already. However,
+ // there seem to be some edge cases where we change our visibility but client visibility
+ // never gets updated.
+ // If we're becoming invisible, update the client visibility if we are not running an
+ // animation. Otherwise, we'll update client visibility in onAnimationFinished.
+ if (visible || !delayed) {
+ setClientHidden(!visible);
}
// If we are hidden but there is no delay needed we immediately
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index 429dd8f..de54e52 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -42,6 +42,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.BatteryManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager.ServiceType;
@@ -51,6 +52,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
@@ -105,6 +107,9 @@
PowerManagerInternal injectPowerManagerInternal() {
return mMockPowerManagerInternal;
}
+
+ @Override
+ boolean isSmallBatteryDevice() { return mIsSmallBatteryDevice; };
}
private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
@@ -144,6 +149,7 @@
private FakeSettingsProvider mFakeSettingsProvider;
private boolean mPowerSaveMode;
+ private boolean mIsSmallBatteryDevice;
private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
@@ -232,6 +238,7 @@
assertNotNull(mAppOpsCallback);
assertNotNull(mPowerSaveObserver);
assertNotNull(mReceiver);
+ assertNotNull(instance.mFlagsObserver);
}
private void setAppOps(int uid, String packageName, boolean restrict) throws RemoteException {
@@ -852,6 +859,56 @@
assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
}
+ @Test
+ public void testSmallBatteryAndPluggedIn() throws Exception {
+ // This is a small battery device
+ mIsSmallBatteryDevice = true;
+
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+ assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+ // Setting/experiment for all app standby for small battery is enabled
+ Global.putInt(mMockContentResolver, Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 1);
+ instance.mFlagsObserver.onChange(true,
+ Global.getUriFor(Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED));
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+ // When battery is plugged in, force app standby is disabled
+ Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+ mReceiver.onReceive(mMockContext, intent);
+ assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+ // When battery stops plugged in, force app standby is enabled
+ mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+ }
+
+ @Test
+ public void testNotSmallBatteryAndPluggedIn() throws Exception {
+ // Not a small battery device, so plugged in status should not affect forced app standby
+ mIsSmallBatteryDevice = false;
+
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+ assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+ // When battery is plugged in, force app standby is unaffected
+ Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+ mReceiver.onReceive(mMockContext, intent);
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+ // When battery stops plugged in, force app standby is unaffected
+ mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+ }
+
static int[] array(int... appIds) {
Arrays.sort(appIds);
return appIds;
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
index 851d2c6..654acc2 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
@@ -33,12 +33,15 @@
import org.junit.runner.RunWith;
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.PrintWriter;
import java.util.Arrays;
+
/**
* runtest frameworks-services -c com.android.server.net.watchlist.WatchlistConfigTests
*/
@@ -117,6 +120,15 @@
assertEquals(TEST_XML_1_HASH, HexDump.toHexString(config.getWatchlistConfigHash()));
}
+ @Test
+ public void testWatchlistConfig_testDumpDoesNotCrash() throws Exception {
+ WatchlistConfig config = new WatchlistConfig(new File("/not_exist_path.xml"));
+ ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+ PrintWriter pw = new PrintWriter(bs);
+ // Make sure dump still works even watchlist does not exist
+ config.dump(null, pw, null);
+ }
+
private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile)
throws IOException {
writeToFile(outFile, readAsset(context, xmlAsset));
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 2534327..d146707 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -71,8 +71,18 @@
* TODO(b/35851809): Make this a SystemApi.
*/
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_OTA_STATUS_CHANGED
- = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+ public static final String ACTION_OTA_STATUS_CHANGED =
+ "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+
+ /**
+ * Broadcast Action: The action sent to carrier app so it knows the carrier setup is not
+ * completed.
+ *
+ * TODO(b/35851809): Make this a public API.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NOTIFY_CARRIER_SETUP =
+ "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP";
/**
* Intent action to provision an embedded subscription.
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 10d6deb..9f2cb92 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -66,6 +66,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -174,6 +175,7 @@
}
@Test
+ @Ignore
public void testDefaultNetworkEvents() throws Exception {
final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
@@ -292,6 +294,7 @@
}
@Test
+ @Ignore
public void testEndToEndLogging() throws Exception {
// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);