summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt48
-rw-r--r--api/system-current.txt45
-rw-r--r--api/test-current.txt57
-rw-r--r--core/java/android/app/AuthenticationRequiredException.java99
-rw-r--r--core/java/android/app/RecoverableSecurityException.java3
-rw-r--r--core/java/android/database/PageViewCursor.java8
-rw-r--r--core/java/android/os/Parcel.java4
-rw-r--r--core/java/android/os/PowerSaveState.java19
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/provider/DocumentsContract.java39
-rw-r--r--core/java/android/provider/DocumentsProvider.java139
-rwxr-xr-xcore/java/android/provider/Settings.java10
-rw-r--r--core/java/android/util/LongSparseArray.java1
-rw-r--r--core/java/android/util/SparseArray.java1
-rw-r--r--core/java/android/widget/ListPopupWindow.java9
-rw-r--r--core/java/android/widget/PopupWindow.java41
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java31
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp50
-rw-r--r--core/res/res/values-ldrtl-television/config.xml4
-rw-r--r--core/res/res/values-television/config.xml4
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--media/java/android/media/MediaRouter.java5
-rw-r--r--media/java/android/media/browse/MediaBrowser.java18
-rw-r--r--media/java/android/media/tv/TvContract.java5
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java7
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java10
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java41
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java176
-rw-r--r--packages/SystemUI/res/drawable/ic_add_circle_qs.xml2
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/Events.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java (renamed from packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java)125
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java (renamed from packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java)62
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java11
-rw-r--r--proto/src/metrics_constants.proto3
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java8
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java10
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java144
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java74
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java20
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java15
-rw-r--r--services/core/java/com/android/server/power/BatterySaverPolicy.java21
-rw-r--r--services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java20
-rw-r--r--services/core/java/com/android/server/security/KeyChainSystemService.java25
-rw-r--r--services/core/java/com/android/server/storage/AppFuseBridge.java159
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java12
-rw-r--r--services/core/jni/com_android_server_storage_AppFuseBridge.cpp110
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java95
-rw-r--r--services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java22
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java70
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl10
-rw-r--r--wifi/java/android/net/wifi/IconInfo.aidl19
-rw-r--r--wifi/java/android/net/wifi/IconInfo.java111
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java21
-rw-r--r--wifi/tests/src/android/net/wifi/IconInfoTest.java122
69 files changed, 1456 insertions, 925 deletions
diff --git a/api/current.txt b/api/current.txt
index 06927c3ea569..b400b34170de 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4297,6 +4297,14 @@ package android.app {
field public java.lang.String serviceDetails;
}
+ public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+ }
+
public final class AutomaticZenRule implements android.os.Parcelable {
ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
ctor public AutomaticZenRule(android.os.Parcel);
@@ -5708,17 +5716,6 @@ package android.app {
field public static final int STYLE_SPINNER = 0; // 0x0
}
- public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
- method public int describeContents();
- method public android.app.RemoteAction getUserAction();
- method public java.lang.CharSequence getUserMessage();
- method public void showAsDialog(android.app.Activity);
- method public void showAsNotification(android.content.Context, java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
- }
-
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
@@ -24621,6 +24618,7 @@ package android.media.tv {
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_LOCKED = "locked";
field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
@@ -26280,16 +26278,6 @@ package android.net.sip {
package android.net.wifi {
- public final class IconInfo implements android.os.Parcelable {
- ctor public IconInfo(java.lang.String, byte[]);
- ctor public IconInfo(android.net.wifi.IconInfo);
- method public int describeContents();
- method public byte[] getData();
- method public java.lang.String getFilename();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
- }
-
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
method public boolean is80211mcResponder();
@@ -26538,7 +26526,8 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
- field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+ field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+ field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
@@ -31197,7 +31186,6 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
- method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -31242,7 +31230,6 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
- method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -34262,6 +34249,7 @@ package android.provider {
method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -34330,6 +34318,7 @@ package android.provider {
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
+ field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20
field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10
field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
@@ -34343,6 +34332,7 @@ package android.provider {
method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public void ejectRoot(java.lang.String);
method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
@@ -39946,13 +39936,17 @@ package android.telephony {
method public int getDataActivity();
method public int getDataNetworkType();
method public int getDataState();
- method public java.lang.String getDeviceId();
- method public java.lang.String getDeviceId(int);
+ method public deprecated java.lang.String getDeviceId();
+ method public deprecated java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getImei();
+ method public java.lang.String getImei(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getMeid();
+ method public java.lang.String getMeid(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
@@ -43241,7 +43235,6 @@ package android.util {
method public E get(long, E);
method public int indexOfKey(long);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public long keyAt(int);
method public void put(long, E);
method public void remove(long);
@@ -43444,7 +43437,6 @@ package android.util {
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index c99ca68e58ec..844b897e4507 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4441,6 +4441,14 @@ package android.app {
field public java.lang.String serviceDetails;
}
+ public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+ }
+
public final class AutomaticZenRule implements android.os.Parcelable {
ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
ctor public AutomaticZenRule(android.os.Parcel);
@@ -5900,17 +5908,6 @@ package android.app {
field public static final int STYLE_SPINNER = 0; // 0x0
}
- public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
- method public int describeContents();
- method public android.app.RemoteAction getUserAction();
- method public java.lang.CharSequence getUserMessage();
- method public void showAsDialog(android.app.Activity);
- method public void showAsNotification(android.content.Context, java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
- }
-
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
@@ -28564,16 +28561,6 @@ package android.net.wifi {
field public boolean truncated;
}
- public final class IconInfo implements android.os.Parcelable {
- ctor public IconInfo(java.lang.String, byte[]);
- ctor public IconInfo(android.net.wifi.IconInfo);
- method public int describeContents();
- method public byte[] getData();
- method public java.lang.String getFilename();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
- }
-
public class RttManager {
method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
@@ -29069,7 +29056,8 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
- field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+ field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+ field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
@@ -33925,7 +33913,6 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
- method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -33970,7 +33957,6 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
- method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -37163,6 +37149,7 @@ package android.provider {
method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -37231,6 +37218,7 @@ package android.provider {
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
+ field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20
field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10
field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
@@ -37244,6 +37232,7 @@ package android.provider {
method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public void ejectRoot(java.lang.String);
method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
@@ -43343,8 +43332,8 @@ package android.telephony {
method public deprecated boolean getDataEnabled(int);
method public int getDataNetworkType();
method public int getDataState();
- method public java.lang.String getDeviceId();
- method public java.lang.String getDeviceId(int);
+ method public deprecated java.lang.String getDeviceId();
+ method public deprecated java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
@@ -43352,6 +43341,8 @@ package android.telephony {
method public java.lang.String getImei();
method public java.lang.String getImei(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getMeid();
+ method public java.lang.String getMeid(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
@@ -46699,7 +46690,6 @@ package android.util {
method public E get(long, E);
method public int indexOfKey(long);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public long keyAt(int);
method public void put(long, E);
method public void remove(long);
@@ -46902,7 +46892,6 @@ package android.util {
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index d1088ddf4dc0..a73ac18ac0c7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4307,6 +4307,14 @@ package android.app {
field public java.lang.String serviceDetails;
}
+ public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+ }
+
public final class AutomaticZenRule implements android.os.Parcelable {
ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
ctor public AutomaticZenRule(android.os.Parcel);
@@ -5719,17 +5727,6 @@ package android.app {
field public static final int STYLE_SPINNER = 0; // 0x0
}
- public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
- method public int describeContents();
- method public android.app.RemoteAction getUserAction();
- method public java.lang.CharSequence getUserMessage();
- method public void showAsDialog(android.app.Activity);
- method public void showAsNotification(android.content.Context, java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
- }
-
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
@@ -11751,6 +11748,15 @@ package android.database {
field protected final java.util.ArrayList<T> mObservers;
}
+ public final class PageViewCursor extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+ ctor public PageViewCursor(android.database.Cursor, int, int);
+ method public void fillWindow(int, android.database.CursorWindow);
+ method public android.database.CursorWindow getWindow();
+ method public boolean onMove(int, int);
+ method public static android.database.Cursor wrap(android.database.Cursor, android.os.Bundle);
+ field public static final java.lang.String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
+ }
+
public class SQLException extends java.lang.RuntimeException {
ctor public SQLException();
ctor public SQLException(java.lang.String);
@@ -24723,6 +24729,7 @@ package android.media.tv {
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_LOCKED = "locked";
field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
@@ -26382,16 +26389,6 @@ package android.net.sip {
package android.net.wifi {
- public final class IconInfo implements android.os.Parcelable {
- ctor public IconInfo(java.lang.String, byte[]);
- ctor public IconInfo(android.net.wifi.IconInfo);
- method public int describeContents();
- method public byte[] getData();
- method public java.lang.String getFilename();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
- }
-
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
method public boolean is80211mcResponder();
@@ -26640,7 +26637,8 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
- field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+ field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+ field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
@@ -31320,7 +31318,6 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
- method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -31365,7 +31362,6 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
- method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -34391,6 +34387,7 @@ package android.provider {
method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -34459,6 +34456,7 @@ package android.provider {
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
+ field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20
field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10
field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
@@ -34472,6 +34470,7 @@ package android.provider {
method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public void ejectRoot(java.lang.String);
method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
@@ -40138,13 +40137,17 @@ package android.telephony {
method public int getDataActivity();
method public int getDataNetworkType();
method public int getDataState();
- method public java.lang.String getDeviceId();
- method public java.lang.String getDeviceId(int);
+ method public deprecated java.lang.String getDeviceId();
+ method public deprecated java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getImei();
+ method public java.lang.String getImei(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getMeid();
+ method public java.lang.String getMeid(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
@@ -43438,7 +43441,6 @@ package android.util {
method public E get(long, E);
method public int indexOfKey(long);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public long keyAt(int);
method public void put(long, E);
method public void remove(long);
@@ -43641,7 +43643,6 @@ package android.util {
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
- method public int indexOfValueByValue(E);
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/core/java/android/app/AuthenticationRequiredException.java b/core/java/android/app/AuthenticationRequiredException.java
new file mode 100644
index 000000000000..89609794a615
--- /dev/null
+++ b/core/java/android/app/AuthenticationRequiredException.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Specialization of {@link SecurityException} that is thrown when authentication is needed from the
+ * end user before viewing the content.
+ * <p>
+ * This exception is only appropriate where there is a concrete action the user can take to
+ * authorize and make forward progress, such as confirming or entering authentication credentials,
+ * or granting access via other means.
+ * <p class="note">
+ * Note: legacy code that receives this exception may treat it as a general
+ * {@link SecurityException}, and thus there is no guarantee that the action contained will be
+ * invoked by the user.
+ * </p>
+ */
+public final class AuthenticationRequiredException extends SecurityException implements Parcelable {
+ private static final String TAG = "AuthenticationRequiredException";
+
+ private final PendingIntent mUserAction;
+
+ /** {@hide} */
+ public AuthenticationRequiredException(Parcel in) {
+ this(new SecurityException(in.readString()), PendingIntent.CREATOR.createFromParcel(in));
+ }
+
+ /**
+ * Create an instance ready to be thrown.
+ *
+ * @param cause original cause with details designed for engineering
+ * audiences.
+ * @param userAction primary action that will initiate the recovery. This
+ * must launch an activity that is expected to set
+ * {@link Activity#setResult(int)} before finishing to
+ * communicate the final status of the recovery. For example,
+ * apps that observe {@link Activity#RESULT_OK} may choose to
+ * immediately retry their operation. If this exception was
+ * thrown from a {@link ContentProvider}, you should also send
+ * any relevant {@link ContentResolver#notifyChange} events to
+ * trigger reloading of data.
+ */
+ public AuthenticationRequiredException(Throwable cause, PendingIntent userAction) {
+ super(cause.getMessage());
+ mUserAction = Preconditions.checkNotNull(userAction);
+ }
+
+ /**
+ * Return primary action that will initiate the authorization.
+ */
+ public PendingIntent getUserAction() {
+ return mUserAction;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(getMessage());
+ mUserAction.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<AuthenticationRequiredException> CREATOR =
+ new Creator<AuthenticationRequiredException>() {
+ @Override
+ public AuthenticationRequiredException createFromParcel(Parcel source) {
+ return new AuthenticationRequiredException(source);
+ }
+
+ @Override
+ public AuthenticationRequiredException[] newArray(int size) {
+ return new AuthenticationRequiredException[size];
+ }
+ };
+}
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
index 8612f186ade4..a503a46a29dc 100644
--- a/core/java/android/app/RecoverableSecurityException.java
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -45,7 +45,8 @@ import com.android.internal.util.Preconditions;
* Note: legacy code that receives this exception may treat it as a general
* {@link SecurityException}, and thus there is no guarantee that the messages
* contained will be shown to the end user.
- * </p>
+ *
+ * @hide
*/
public final class RecoverableSecurityException extends SecurityException implements Parcelable {
private static final String TAG = "RecoverableSecurityException";
diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java
index 5f42f30be5ba..44727a0d300e 100644
--- a/core/java/android/database/PageViewCursor.java
+++ b/core/java/android/database/PageViewCursor.java
@@ -18,13 +18,13 @@ package android.database;
import static com.android.internal.util.Preconditions.checkArgument;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.ContentResolver;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.MathUtils;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
/**
@@ -34,11 +34,10 @@ import com.android.internal.util.ArrayUtils;
*
* @hide
*/
+@TestApi
public final class PageViewCursor extends CursorWrapper implements CrossProcessCursor {
- /**
- * An in internal extra added to results that are auto-paged using the wrapper.
- */
+ /** An extra added to results that are auto-paged using the wrapper. */
public static final String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
private static final String TAG = "PageViewCursor";
@@ -56,7 +55,6 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
/**
* @see PageViewCursor#wrap(Cursor, Bundle)
*/
- @VisibleForTesting
public PageViewCursor(Cursor cursor, int offset, int limit) {
super(cursor);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 7a39d239f84b..2e35a51afe46 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -898,6 +898,9 @@ public final class Parcel {
}
}
+ /**
+ * @hide
+ */
public final void writeSparseIntArray(SparseIntArray val) {
if (val == null) {
writeInt(-1);
@@ -2323,6 +2326,7 @@ public final class Parcel {
/**
* Read and return a new SparseIntArray object from the parcel at the current
* dataPosition(). Returns null if the previously written array object was null.
+ * @hide
*/
public final SparseIntArray readSparseIntArray() {
int N = readInt();
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index 9269e762ef4c..7058a1dca34d 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -24,7 +24,17 @@ package android.os;
* @hide
*/
public class PowerSaveState implements Parcelable {
+ /**
+ * Whether we should enable battery saver for this service.
+ *
+ * @see com.android.server.power.BatterySaverPolicy.ServiceType
+ */
public final boolean batterySaverEnabled;
+ /**
+ * Whether the battery saver is enabled globally, which means the data we get from
+ * {@link PowerManager#isPowerSaveMode()}
+ */
+ public final boolean globalBatterySaverEnabled;
public final int gpsMode;
public final float brightnessFactor;
@@ -32,10 +42,12 @@ public class PowerSaveState implements Parcelable {
batterySaverEnabled = builder.mBatterySaverEnabled;
gpsMode = builder.mGpsMode;
brightnessFactor = builder.mBrightnessFactor;
+ globalBatterySaverEnabled = builder.mGlobalBatterySaverEnabled;
}
public PowerSaveState(Parcel in) {
batterySaverEnabled = in.readByte() != 0;
+ globalBatterySaverEnabled = in.readByte() != 0;
gpsMode = in.readInt();
brightnessFactor = in.readFloat();
}
@@ -48,12 +60,14 @@ public class PowerSaveState implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (batterySaverEnabled ? 1 : 0));
+ dest.writeByte((byte) (globalBatterySaverEnabled ? 1 : 0));
dest.writeInt(gpsMode);
dest.writeFloat(brightnessFactor);
}
public static final class Builder {
private boolean mBatterySaverEnabled = false;
+ private boolean mGlobalBatterySaverEnabled = false;
private int mGpsMode = 0;
private float mBrightnessFactor = 0.5f;
@@ -64,6 +78,11 @@ public class PowerSaveState implements Parcelable {
return this;
}
+ public Builder setGlobalBatterySaverEnabled(boolean enabled) {
+ mGlobalBatterySaverEnabled = enabled;
+ return this;
+ }
+
public Builder setGpsMode(int mode) {
mGpsMode = mode;
return this;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f69c996c5368..31376587e144 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -92,6 +92,12 @@ public class Process {
public static final int VPN_UID = 1016;
/**
+ * Defines the UID/GID for keystore.
+ * @hide
+ */
+ public static final int KEYSTORE_UID = 1017;
+
+ /**
* Defines the UID/GID for the NFC service process.
* @hide
*/
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 9e56e01c24c4..fa9038411010 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -594,6 +594,15 @@ public final class DocumentsContract {
public static final int FLAG_SUPPORTS_IS_CHILD = 1 << 4;
/**
+ * Flag indicating that this root can be ejected.
+ *
+ * @see #COLUMN_FLAGS
+ * @see DocumentsContract#ejectRoot(ContentResolver, Uri)
+ * @see DocumentsProvider#ejectRoot(String)
+ */
+ public static final int FLAG_SUPPORTS_EJECT = 1 << 5;
+
+ /**
* Flag indicating that this root is currently empty. This may be used
* to hide the root when opening documents, but the root will still be
* shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
@@ -641,9 +650,6 @@ public final class DocumentsContract {
* @hide
*/
public static final int FLAG_REMOVABLE_USB = 1 << 20;
-
- /** {@hide} */
- public static final int FLAG_SUPPORTS_EJECT = 1 << 21;
}
/**
@@ -1345,35 +1351,30 @@ public final class DocumentsContract {
client.call(METHOD_REMOVE_DOCUMENT, null, in);
}
- /** {@hide} */
- public static boolean ejectRoot(ContentResolver resolver, Uri rootUri) {
+ /**
+ * Ejects the given root. It throws {@link IllegalStateException} when ejection failed.
+ *
+ * @param rootUri root with {@link Root#FLAG_SUPPORTS_EJECT} to be ejected
+ */
+ public static void ejectRoot(ContentResolver resolver, Uri rootUri) {
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
rootUri.getAuthority());
try {
- return ejectRoot(client, rootUri);
- } catch (Exception e) {
- Log.w(TAG, "Failed to eject root", e);
- return false;
+ ejectRoot(client, rootUri);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
} finally {
ContentProviderClient.releaseQuietly(client);
}
}
/** {@hide} */
- public static boolean ejectRoot(ContentProviderClient client, Uri rootUri)
+ public static void ejectRoot(ContentProviderClient client, Uri rootUri)
throws RemoteException {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
- final Bundle out = client.call(METHOD_EJECT_ROOT, null, in);
-
- if (out == null) {
- throw new RemoteException("Failed to get a reponse from ejectRoot.");
- }
- if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
- throw new RemoteException("Response did not include result field..");
- }
- return out.getBoolean(DocumentsContract.EXTRA_RESULT);
+ client.call(METHOD_EJECT_ROOT, null, in);
}
/**
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 620d33a5e915..2a83c4b6a6ba 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -38,7 +38,7 @@ import static android.provider.DocumentsContract.isTreeUri;
import android.Manifest;
import android.annotation.CallSuper;
import android.annotation.Nullable;
-import android.app.RecoverableSecurityException;
+import android.app.AuthenticationRequiredException;
import android.content.ClipDescription;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -235,10 +235,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new
* {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must
* not change once returned.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param parentDocumentId the parent directory to create the new document
* under.
@@ -247,6 +243,10 @@ public abstract class DocumentsProvider extends ContentProvider {
* @param displayName the display name of the new document. The provider may
* alter this name to meet any internal constraints, such as
* avoiding conflicting names.
+
+ * @throws AuthenticationRequiredException If authentication is required from the user (such as
+ * login credentials), but it is not guaranteed that the client will handle this
+ * properly.
*/
@SuppressWarnings("unused")
public String createDocument(String parentDocumentId, String mimeType, String displayName)
@@ -262,15 +262,14 @@ public abstract class DocumentsProvider extends ContentProvider {
* URI permission grants will be updated to point at the new document. If
* the original {@link Document#COLUMN_DOCUMENT_ID} is still valid after the
* rename, return {@code null}.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param documentId the document to rename.
* @param displayName the updated display name of the document. The provider
* may alter this name to meet any internal constraints, such as
* avoiding conflicting names.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
@SuppressWarnings("unused")
public String renameDocument(String documentId, String displayName)
@@ -286,12 +285,11 @@ public abstract class DocumentsProvider extends ContentProvider {
* call (such as documents inside a directory) the implementor is
* responsible for revoking those permissions using
* {@link #revokeDocumentPermission(String)}.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param documentId the document to delete.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
@SuppressWarnings("unused")
public void deleteDocument(String documentId) throws FileNotFoundException {
@@ -305,13 +303,12 @@ public abstract class DocumentsProvider extends ContentProvider {
* the same document provider. Upon completion returns the document id of
* the copied document at the target destination. {@code null} must never
* be returned.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param sourceDocumentId the document to copy.
* @param targetParentDocumentId the target document to be copied into as a child.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
@SuppressWarnings("unused")
public String copyDocument(String sourceDocumentId, String targetParentDocumentId)
@@ -329,15 +326,14 @@ public abstract class DocumentsProvider extends ContentProvider {
*
* <p>It's the responsibility of the provider to revoke grants if the document
* is no longer accessible using <code>sourceDocumentId</code>.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param sourceDocumentId the document to move.
* @param sourceParentDocumentId the parent of the document to move.
* @param targetParentDocumentId the target document to be a new parent of the
* source document.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
@SuppressWarnings("unused")
public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
@@ -355,11 +351,11 @@ public abstract class DocumentsProvider extends ContentProvider {
* <p>It's the responsibility of the provider to revoke grants if the document is
* removed from the last parent, and effectively the document is deleted.
*
- * <p>{@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
* @param documentId the document to remove.
* @param parentDocumentId the parent of the document to move.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
@SuppressWarnings("unused")
public void removeDocument(String documentId, String parentDocumentId)
@@ -377,9 +373,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* <p>This API assumes that document ID has enough info to infer the root.
* Different roots should use different document ID to refer to the same
* document.
- * <p>{@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.perly.
*
*
* @param parentDocumentId the document from which the path starts if not null,
@@ -388,6 +381,9 @@ public abstract class DocumentsProvider extends ContentProvider {
* @return the path of the requested document. If parentDocumentId is null
* returned root ID must not be null. If parentDocumentId is not null
* returned root ID must be null.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
public Path findDocumentPath(@Nullable String parentDocumentId, String childDocumentId)
throws FileNotFoundException {
@@ -397,7 +393,7 @@ public abstract class DocumentsProvider extends ContentProvider {
/**
* Creates an intent sender for a web link, if the document is web linkable.
* <p>
- * {@link RecoverableSecurityException} can be thrown if user does not have
+ * {@link AuthenticationRequiredException} can be thrown if user does not have
* sufficient permission for the linked document. Before any new permissions
* are granted for the linked document, a visible UI must be shown, so the
* user can explicitly confirm whether the permission grants are expected.
@@ -414,6 +410,9 @@ public abstract class DocumentsProvider extends ContentProvider {
*
* @param documentId the document to create a web link intent for.
* @param options additional information, such as list of recipients. Optional.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*
* @see DocumentsContract.Document#FLAG_WEB_LINKABLE
* @see android.app.PendingIntent#getIntentSender
@@ -436,9 +435,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* android.database.ContentObserver, boolean)} with
* {@link DocumentsContract#buildRootsUri(String)} to notify the system.
* <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
*
* @param projection list of {@link Root} columns to put into the cursor. If
* {@code null} all supported columns should be included.
@@ -452,10 +448,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and
* limited to only return the 64 most recently modified documents.
* <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
- * <p>
* Recent documents do not support change notifications.
*
* @param projection list of {@link Document} columns to put into the
@@ -472,16 +464,14 @@ public abstract class DocumentsProvider extends ContentProvider {
/**
* Return metadata for the single requested document. You should avoid
* making network requests to keep this request fast.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
- *
*
* @param documentId the document to return.
* @param projection list of {@link Document} columns to put into the
* cursor. If {@code null} all supported columns should be
* included.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
public abstract Cursor queryDocument(String documentId, String[] projection)
throws FileNotFoundException;
@@ -509,11 +499,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* you can call {@link ContentResolver#notifyChange(Uri,
* android.database.ContentObserver, boolean)} with that Uri to send change
* notifications.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
- *
*
* @param parentDocumentId the directory to return children for.
* @param projection list of {@link Document} columns to put into the
@@ -525,6 +510,9 @@ public abstract class DocumentsProvider extends ContentProvider {
* may be unordered. This ordering is a hint that can be used to
* prioritize how data is fetched from the network, but UI may
* always enforce a specific ordering.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
* @see DocumentsContract#EXTRA_LOADING
* @see DocumentsContract#EXTRA_INFO
* @see DocumentsContract#EXTRA_ERROR
@@ -552,10 +540,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* you can call {@link ContentResolver#notifyChange(Uri,
* android.database.ContentObserver, boolean)} with that Uri to send change
* notifications.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
*
* @param parentDocumentId the directory to return children for.
* @param projection list of {@link Document} columns to put into the
@@ -567,6 +551,9 @@ public abstract class DocumentsProvider extends ContentProvider {
* will be used, which may be unordered. See
* {@link ContentResolver#QUERY_ARG_SORT_COLUMNS} for
* details.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*
* @see DocumentsContract#EXTRA_LOADING
* @see DocumentsContract#EXTRA_INFO
@@ -609,16 +596,16 @@ public abstract class DocumentsProvider extends ContentProvider {
* String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri,
* android.database.ContentObserver, boolean)} with that Uri to send change
* notifications.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), or returned as part of
- * Cursor's bundle. It is not guaranteed that the client will handle this properly.
*
* @param rootId the root to search under.
* @param query string to match documents against.
* @param projection list of {@link Document} columns to put into the
* cursor. If {@code null} all supported columns should be
* included.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
+ *
* @see DocumentsContract#EXTRA_LOADING
* @see DocumentsContract#EXTRA_INFO
* @see DocumentsContract#EXTRA_ERROR
@@ -629,9 +616,14 @@ public abstract class DocumentsProvider extends ContentProvider {
throw new UnsupportedOperationException("Search not supported");
}
- /** {@hide} */
+ /**
+ * Ejects the root. Throws {@link IllegalStateException} if ejection failed.
+ *
+ * @param rootId the root to be ejected.
+ * @see Root#FLAG_SUPPORTS_EJECT
+ */
@SuppressWarnings("unused")
- public boolean ejectRoot(String rootId) {
+ public void ejectRoot(String rootId) {
throw new UnsupportedOperationException("Eject not supported");
}
@@ -641,9 +633,9 @@ public abstract class DocumentsProvider extends ContentProvider {
* implementation queries {@link #queryDocument(String, String[])}, so
* providers may choose to override this as an optimization.
* <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
*/
public String getDocumentType(String documentId) throws FileNotFoundException {
final Cursor cursor = queryDocument(documentId, null);
@@ -669,15 +661,14 @@ public abstract class DocumentsProvider extends ContentProvider {
* <p>
* If you block while downloading content, you should periodically check
* {@link CancellationSignal#isCanceled()} to abort abandoned open requests.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param documentId the document to return.
* @param mode the mode to open with, such as 'r', 'w', or 'rw'.
* @param signal used by the caller to signal if the request should be
* cancelled. May be null.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
* @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
* OnCloseListener)
* @see ParcelFileDescriptor#createReliablePipe()
@@ -697,15 +688,14 @@ public abstract class DocumentsProvider extends ContentProvider {
* If you perform expensive operations to download or generate a thumbnail,
* you should periodically check {@link CancellationSignal#isCanceled()} to
* abort abandoned thumbnail requests.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param documentId the document to return.
* @param sizeHint hint of the optimal thumbnail dimensions.
* @param signal used by the caller to signal if the request should be
* cancelled. May be null.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
* @see Document#FLAG_SUPPORTS_THUMBNAIL
*/
@SuppressWarnings("unused")
@@ -723,10 +713,6 @@ public abstract class DocumentsProvider extends ContentProvider {
* matching the specified MIME type filter.
* <p>
* Virtual documents must have at least one streamable format.
- * <p>
- * {@link RecoverableSecurityException} can be thrown if more input is required
- * from the user (such as insufficient permission), but it is not guaranteed that
- * the client will handle this properly.
*
* @param documentId the document to return.
* @param mimeTypeFilter the MIME type filter for the requested format. May
@@ -735,6 +721,9 @@ public abstract class DocumentsProvider extends ContentProvider {
* provider.
* @param signal used by the caller to signal if the request should be
* cancelled. May be null.
+ * @throws AuthenticationRequiredException If authentication is required from
+ * the user (such as login credentials), but it is not guaranteed
+ * that the client will handle this properly.
* @see #getDocumentStreamTypes(String, String)
*/
@SuppressWarnings("unused")
@@ -963,14 +952,12 @@ public abstract class DocumentsProvider extends ContentProvider {
if (METHOD_EJECT_ROOT.equals(method)) {
// Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps
// signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
- // MANAGE_DOCUMENTS here instead
- getContext().enforceCallingPermission(
- android.Manifest.permission.MANAGE_DOCUMENTS, null);
+ // MANAGE_DOCUMENTS or associated URI permission here instead
final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
- final String rootId = DocumentsContract.getRootId(rootUri);
- final boolean ejected = ejectRoot(rootId);
+ enforceWritePermissionInner(rootUri, getCallingPackage(), null);
- out.putBoolean(DocumentsContract.EXTRA_RESULT, ejected);
+ final String rootId = DocumentsContract.getRootId(rootUri);
+ ejectRoot(rootId);
return out;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 146d2d3caebc..83528741dd82 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9741,6 +9741,16 @@ public final class Settings {
public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
/**
+ * The build id of when the settings database was first created (or re-created due it
+ * being missing).
+ *
+ * Type: string
+ *
+ * @hide
+ */
+ public static final String DATABASE_CREATION_BUILDID = "database_creation_buildid";
+
+ /**
* Flag to toggle journal mode WAL on or off for the contacts database. WAL is enabled by
* default. Set to 0 to disable.
*
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 58ad2fd0c586..9ba0f5da135e 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -315,6 +315,7 @@ public class LongSparseArray<E> implements Cloneable {
* and that multiple keys can map to the same value and this will
* find only one of them.
* <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
+ * @hide
*/
public int indexOfValueByValue(E value) {
if (mGarbage) {
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index c76666069d18..b3400ef538b8 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -363,6 +363,7 @@ public class SparseArray<E> implements Cloneable {
* and that multiple keys can map to the same value and this will
* find only one of them.
* <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
+ * @hide
*/
public int indexOfValueByValue(E value) {
if (mGarbage) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 7b99d07d2457..78d18fdbca5f 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -75,6 +75,7 @@ public class ListPopupWindow implements ShowableListMenu {
private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
private boolean mDropDownVerticalOffsetSet;
private boolean mIsAnimatedFromAnchor = true;
+ private boolean mOverlapAnchor;
private int mDropDownGravity = Gravity.NO_GRAVITY;
@@ -672,6 +673,7 @@ public class ListPopupWindow implements ShowableListMenu {
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.setTouchInterceptor(mTouchInterceptor);
mPopup.setEpicenterBounds(mEpicenterBounds);
+ mPopup.setOverlapAnchor(mOverlapAnchor);
mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
mDropDownVerticalOffset, mDropDownGravity);
mDropDownList.setSelection(ListView.INVALID_POSITION);
@@ -1245,6 +1247,13 @@ public class ListPopupWindow implements ShowableListMenu {
return listContent + otherHeights;
}
+ /**
+ * @hide
+ */
+ public void setOverlapAnchor(boolean overlap) {
+ mOverlapAnchor = overlap;
+ }
+
private class PopupDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 26b3ae2c42fc..9f10531841e3 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -55,6 +55,7 @@ import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.WindowManagerGlobal;
import com.android.internal.R;
@@ -137,6 +138,7 @@ public class PopupWindow {
private final int[] mTmpDrawingLocation = new int[2];
private final int[] mTmpScreenLocation = new int[2];
+ private final int[] mTmpAppLocation = new int[2];
private final Rect mTempRect = new Rect();
private Context mContext;
@@ -242,6 +244,9 @@ public class PopupWindow {
private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor;
+ private final View.OnLayoutChangeListener mOnLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> alignToAnchor();
+
private int mAnchorXoff;
private int mAnchorYoff;
private int mAnchoredGravity;
@@ -1238,7 +1243,8 @@ public class PopupWindow {
mIsShowing = true;
mIsDropdown = true;
- final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
+ final WindowManager.LayoutParams p =
+ createPopupLayoutParams(anchor.getApplicationWindowToken());
preparePopup(p);
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
@@ -1547,13 +1553,21 @@ public class PopupWindow {
}
// Initially, align to the bottom-left corner of the anchor plus offsets.
+ final int[] appScreenLocation = mTmpAppLocation;
+ final View appRootView = getAppRootView(anchor);
+ appRootView.getLocationOnScreen(appScreenLocation);
+
+ final int[] screenLocation = mTmpScreenLocation;
+ anchor.getLocationOnScreen(screenLocation);
+
final int[] drawingLocation = mTmpDrawingLocation;
- anchor.getLocationInWindow(drawingLocation);
+ drawingLocation[0] = screenLocation[0] - appScreenLocation[0];
+ drawingLocation[1] = screenLocation[1] - appScreenLocation[1];
outParams.x = drawingLocation[0] + xOffset;
outParams.y = drawingLocation[1] + anchorHeight + yOffset;
final Rect displayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(displayFrame);
+ appRootView.getWindowVisibleDisplayFrame(displayFrame);
if (width == MATCH_PARENT) {
width = displayFrame.right - displayFrame.left;
}
@@ -1574,9 +1588,6 @@ public class PopupWindow {
outParams.x -= width - anchorWidth;
}
- final int[] screenLocation = mTmpScreenLocation;
- anchor.getLocationOnScreen(screenLocation);
-
// First, attempt to fit the popup vertically without resizing.
final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
@@ -1595,7 +1606,9 @@ public class PopupWindow {
scrollY + height + anchorHeight + yOffset);
if (allowScroll && anchor.requestRectangleOnScreen(r, true)) {
// Reset for the new anchor position.
- anchor.getLocationInWindow(drawingLocation);
+ anchor.getLocationOnScreen(screenLocation);
+ drawingLocation[0] = screenLocation[0] - appScreenLocation[0];
+ drawingLocation[1] = screenLocation[1] - appScreenLocation[1];
outParams.x = drawingLocation[0] + xOffset;
outParams.y = drawingLocation[1] + anchorHeight + yOffset;
@@ -1793,7 +1806,8 @@ public class PopupWindow {
Rect displayFrame = null;
final Rect visibleDisplayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame);
+ final View appView = getAppRootView(anchor);
+ appView.getWindowVisibleDisplayFrame(visibleDisplayFrame);
if (ignoreBottomDecorations) {
// In the ignore bottom decorations case we want to
// still respect all other decorations so we use the inset visible
@@ -2240,6 +2254,7 @@ public class PopupWindow {
final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null;
if (anchorRoot != null) {
anchorRoot.removeOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
+ anchorRoot.removeOnLayoutChangeListener(mOnLayoutChangeListener);
}
mAnchor = null;
@@ -2258,6 +2273,7 @@ public class PopupWindow {
final View anchorRoot = anchor.getRootView();
anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
+ anchorRoot.addOnLayoutChangeListener(mOnLayoutChangeListener);
mAnchor = new WeakReference<>(anchor);
mAnchorRoot = new WeakReference<>(anchorRoot);
@@ -2281,6 +2297,15 @@ public class PopupWindow {
}
}
+ private View getAppRootView(View anchor) {
+ final View appWindowView = WindowManagerGlobal.getInstance().getWindowView(
+ anchor.getApplicationWindowToken());
+ if (appWindowView != null) {
+ return appWindowView;
+ }
+ return anchor.getRootView();
+ }
+
private class PopupDecorView extends FrameLayout {
private TransitionListenerAdapter mPendingExitListener;
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ebcec5cb5a42..6dff8b41eeb4 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -381,6 +381,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
if (parentView != null) {
// This menu is a cascading submenu anchored to a parent view.
+ popupWindow.setAnchorView(parentView);
popupWindow.setTouchModal(false);
popupWindow.setEnterTransition(null);
@@ -388,42 +389,30 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
mLastPosition = nextMenuPosition;
- // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
- final int[] offsetOrigin = new int[2];
- mAnchorView.getLocationOnScreen(offsetOrigin);
- offsetOrigin[1] += mAnchorView.getHeight();
-
- final int[] parentViewScreenLocation = new int[2];
- parentView.getLocationOnScreen(parentViewScreenLocation);
-
- // Translate the parent view location into the offset coordinate space.
- // If used as horizontal/vertical offsets, these values would position the submenu
- // at the exact same position as the parent item.
- final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
- final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
-
- // Adjust the horizontal offset to display the submenu to the right or to the left
+ // Compute the horizontal offset to display the submenu to the right or to the left
// of the parent item.
// By now, mDropDownGravity is the resolved absolute gravity, so
// this should work in both LTR and RTL.
final int x;
if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) {
if (showOnRight) {
- x = parentOffsetLeft + menuWidth;
+ x = menuWidth;
} else {
- x = parentOffsetLeft - parentView.getWidth();
+ x = -parentView.getWidth();
}
} else {
if (showOnRight) {
- x = parentOffsetLeft + parentView.getWidth();
+ x = parentView.getWidth();
} else {
- x = parentOffsetLeft - menuWidth;
+ x = -menuWidth;
}
}
popupWindow.setHorizontalOffset(x);
- // Use the same vertical offset as the parent item.
- popupWindow.setVerticalOffset(parentOffsetTop);
+ // Align with the top edge of the parent view (or the bottom edge when the submenu is
+ // flipped vertically).
+ popupWindow.setOverlapAnchor(true);
+ popupWindow.setVerticalOffset(0);
} else {
if (mHasXOffset) {
popupWindow.setHorizontalOffset(mXOffset);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index a8d683028c13..de5e505af3da 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -621,7 +621,7 @@ static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*
const uint8_t* s = (const uint8_t*)src;
do {
uint8_t c = *s++;
- *dst++ = SkColorSetARGB(c, c, c, c);
+ *dst++ = SkColorSetARGB(c, 0, 0, 0);
} while (--width != 0);
}
@@ -727,6 +727,50 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
}
+static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
+ SkBitmap::Allocator* alloc) {
+ // Skia does not support copying from kAlpha8 to types that are not alpha only.
+ // We will handle this case here.
+ if (kAlpha_8_SkColorType == src.colorType() && kAlpha_8_SkColorType != dstCT) {
+ SkAutoPixmapUnlock srcUnlocker;
+ if (!src.requestLock(&srcUnlocker)) {
+ return false;
+ }
+ SkPixmap srcPixmap = srcUnlocker.pixmap();
+
+ SkImageInfo dstInfo = src.info().makeColorType(dstCT);
+ if (!dst->setInfo(dstInfo)) {
+ return false;
+ }
+ if (!dst->tryAllocPixels(alloc, nullptr)) {
+ return false;
+ }
+
+ switch (dstCT) {
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType: {
+ for (int y = 0; y < src.height(); y++) {
+ const uint8_t* srcRow = srcPixmap.addr8(0, y);
+ uint32_t* dstRow = dst->getAddr32(0, y);
+ ToColor_SA8(dstRow, srcRow, src.width(), nullptr);
+ }
+ return true;
+ }
+ case kRGB_565_SkColorType: {
+ for (int y = 0; y < src.height(); y++) {
+ uint16_t* dstRow = dst->getAddr16(0, y);
+ memset(dstRow, 0, sizeof(uint16_t) * src.width());
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+ }
+
+ return src.copyTo(dst, dstCT, alloc);
+}
+
static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
jint dstConfigHandle, jboolean isMutable) {
SkBitmap src;
@@ -743,7 +787,7 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
SkBitmap result;
HeapAllocator allocator;
- if (!src.copyTo(&result, dstCT, &allocator)) {
+ if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
return NULL;
}
auto bitmap = allocator.getStorageObjAndReset();
@@ -754,7 +798,7 @@ static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& ds
SkBitmap result;
AshmemPixelAllocator allocator(env);
- if (!src.copyTo(&result, dstCT, &allocator)) {
+ if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
return NULL;
}
auto bitmap = allocator.getStorageObjAndReset();
diff --git a/core/res/res/values-ldrtl-television/config.xml b/core/res/res/values-ldrtl-television/config.xml
index 503b9022aa3c..2a5a0c9a1f76 100644
--- a/core/res/res/values-ldrtl-television/config.xml
+++ b/core/res/res/values-ldrtl-television/config.xml
@@ -22,7 +22,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.TOP | Gravity.LEFT -->
- <integer name="config_defaultPictureInPictureGravity">0x33</integer>
+ Currently, this maps to Gravity.BOTTOM | Gravity.LEFT -->
+ <integer name="config_defaultPictureInPictureGravity">0x53</integer>
</resources>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 1987ac454d86..78eeee99150a 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -34,6 +34,6 @@
<string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">56x27</string>
<!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.TOP | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x35</integer>
+ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x55</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d1c590069c94..f959df9b85f9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4255,7 +4255,7 @@
<string name="date_picker_day_typeface">sans-serif-medium</string>
<!-- Notify use that they are in Lock-to-app -->
- <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back and Overview.</string>
+ <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back and Overview buttons.</string>
<!-- Notify user that they are locked in lock-to-app mode -->
<string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
<!-- Starting lock-to-app indication. -->
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0cfdaf5d3cab..3e33dd8e8409 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -141,6 +141,7 @@ public class SettingsBackupTest {
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ Settings.Global.DATABASE_CREATION_BUILDID,
Settings.Global.DATABASE_DOWNGRADE_REASON,
Settings.Global.DATA_ROAMING,
Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index a84cee8dbce2..44494a644178 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -141,6 +141,11 @@ public class MediaRouter {
mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name;
mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
mDefaultAudioVideo.updatePresentationDisplay();
+ if (((AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE))
+ .isVolumeFixed()) {
+ mDefaultAudioVideo.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
+ }
+
addRouteStatic(mDefaultAudioVideo);
// This will select the active wifi display route if there is one.
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 7122eaf3563b..5bf205e12799 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -87,10 +87,11 @@ public final class MediaBrowser {
*/
public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
- private static final int CONNECT_STATE_DISCONNECTED = 0;
- private static final int CONNECT_STATE_CONNECTING = 1;
- private static final int CONNECT_STATE_CONNECTED = 2;
- private static final int CONNECT_STATE_SUSPENDED = 3;
+ private static final int CONNECT_STATE_DISCONNECTING = 0;
+ private static final int CONNECT_STATE_DISCONNECTED = 1;
+ private static final int CONNECT_STATE_CONNECTING = 2;
+ private static final int CONNECT_STATE_CONNECTED = 3;
+ private static final int CONNECT_STATE_SUSPENDED = 4;
private final Context mContext;
private final ComponentName mServiceComponent;
@@ -213,6 +214,7 @@ public final class MediaBrowser {
// It's ok to call this any state, because allowing this lets apps not have
// to check isConnected() unnecessarily. They won't appreciate the extra
// assertions for this. We do everything we can here to go back to a sane state.
+ mState = CONNECT_STATE_DISCONNECTING;
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -535,7 +537,7 @@ public final class MediaBrowser {
// If we are connected, tell the service that we are watching. If we aren't connected,
// the service will be told when we connect.
- if (mState == CONNECT_STATE_CONNECTED) {
+ if (isConnected()) {
try {
if (options == null) {
mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
@@ -563,7 +565,7 @@ public final class MediaBrowser {
// Tell the service if necessary.
try {
if (callback == null) {
- if (mState == CONNECT_STATE_CONNECTED) {
+ if (isConnected()) {
mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
}
@@ -572,7 +574,7 @@ public final class MediaBrowser {
final List<Bundle> optionsList = sub.getOptionsList();
for (int i = callbacks.size() - 1; i >= 0; --i) {
if (callbacks.get(i) == callback) {
- if (mState == CONNECT_STATE_CONNECTED) {
+ if (isConnected()) {
mServiceBinder.removeSubscription(
parentId, callback.mToken, mServiceCallbacks);
}
@@ -597,6 +599,8 @@ public final class MediaBrowser {
*/
private static String getStateLabel(int state) {
switch (state) {
+ case CONNECT_STATE_DISCONNECTING:
+ return "CONNECT_STATE_DISCONNECTING";
case CONNECT_STATE_DISCONNECTED:
return "CONNECT_STATE_DISCONNECTED";
case CONNECT_STATE_CONNECTING:
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index c28aa5ec8711..6808b57c2642 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1971,10 +1971,11 @@ public final class TvContract {
* channel is not locked thus the user is not prompted to enter passcode If not specified,
* this value is set to 0 (not locked) by default.
*
+ * <p>This column can only be set by applications having proper system permission to
+ * modify parental control settings. For other applications, this is a read-only column.
+
* <p>Type: INTEGER (boolean)
- * @hide
*/
- @SystemApi
public static final String COLUMN_LOCKED = "locked";
/**
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8802010c06d0..b60e2fefd6e7 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -480,21 +480,18 @@ public class ExternalStorageProvider extends FileSystemProvider {
}
@Override
- public boolean ejectRoot(String rootId) {
+ public void ejectRoot(String rootId) {
final long token = Binder.clearCallingIdentity();
- boolean ejected = false;
RootInfo root = mRoots.get(rootId);
if (root != null) {
try {
mStorageManager.unmount(root.volumeId);
- ejected = true;
} catch (RuntimeException e) {
- Log.w(TAG, "Root '" + root.title + "' could not be ejected");
+ throw new IllegalStateException(e);
} finally {
Binder.restoreCallingIdentity(token);
}
}
- return ejected;
}
@Override
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1f1c18976edf..1a752f924425 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2037,6 +2037,8 @@ public class SettingsProvider extends ContentProvider {
private final BackupManager mBackupManager;
+ private String mSettingsCreationBuildId;
+
public SettingsRegistry() {
mHandler = new MyHandler(getContext().getMainLooper());
mGenerationRegistry = new GenerationRegistry(mLock);
@@ -2502,6 +2504,8 @@ public class SettingsProvider extends ContentProvider {
return;
}
+ mSettingsCreationBuildId = Build.ID;
+
final long identity = Binder.clearCallingIdentity();
try {
List<UserInfo> users = mUserManager.getUsers(true);
@@ -2570,6 +2574,12 @@ public class SettingsProvider extends ContentProvider {
ensureSettingsStateLocked(globalKey);
SettingsState globalSettings = mSettingsStates.get(globalKey);
migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
+ // If this was just created
+ if (mSettingsCreationBuildId != null) {
+ globalSettings.insertSettingLocked(Settings.Global.DATABASE_CREATION_BUILDID,
+ mSettingsCreationBuildId, null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
globalSettings.persistSyncLocked();
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java
new file mode 100644
index 000000000000..9e5db73cf885
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.VolumeDialog.Callback;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * This interface is really just a stub for initialization/teardown, actual handling of
+ * when to show will be done through {@link VolumeDialogController}
+ */
+@ProvidesInterface(action = VolumeDialog.ACTION, version = VolumeDialog.VERSION)
+@DependsOn(target = Callback.class)
+public interface VolumeDialog extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_VOLUME";
+ int VERSION = 1;
+
+ void init(int windowType, Callback callback);
+ void destroy();
+
+ @ProvidesInterface(version = VERSION)
+ public interface Callback {
+ int VERSION = 1;
+
+ void onZenSettingsClicked();
+ void onZenPrioritySettingsClicked();
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
new file mode 100644
index 000000000000..903ff7276101
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.plugins;
+
+import android.annotation.IntegerRes;
+import android.content.ComponentName;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.os.Handler;
+import android.util.SparseArray;
+
+import com.android.systemui.plugins.VolumeDialogController.Callbacks;
+import com.android.systemui.plugins.VolumeDialogController.State;
+import com.android.systemui.plugins.VolumeDialogController.StreamState;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Manages the VolumeDialog.
+ *
+ * Accessible through {@link PluginDependency}
+ */
+@ProvidesInterface(version = VolumeDialogController.VERSION)
+@DependsOn(target = StreamState.class)
+@DependsOn(target = State.class)
+@DependsOn(target = Callbacks.class)
+public interface VolumeDialogController {
+ int VERSION = 1;
+
+ void setActiveStream(int stream);
+ void setStreamVolume(int stream, int userLevel);
+ void setRingerMode(int ringerModeNormal, boolean external);
+
+ boolean hasVibrator();
+ void vibrate();
+
+ AudioManager getAudioManager();
+
+ void notifyVisible(boolean visible);
+
+ void addCallback(Callbacks callbacks, Handler handler);
+ void removeCallback(Callbacks callbacks);
+
+ void userActivity();
+ void getState();
+
+ @ProvidesInterface(version = StreamState.VERSION)
+ public static final class StreamState {
+ public static final int VERSION = 1;
+
+ public boolean dynamic;
+ public int level;
+ public int levelMin;
+ public int levelMax;
+ public boolean muted;
+ public boolean muteSupported;
+ public @IntegerRes int name;
+ public String remoteLabel;
+ public boolean routedToBluetooth;
+
+ public StreamState copy() {
+ final StreamState rt = new StreamState();
+ rt.dynamic = dynamic;
+ rt.level = level;
+ rt.levelMin = levelMin;
+ rt.levelMax = levelMax;
+ rt.muted = muted;
+ rt.muteSupported = muteSupported;
+ rt.name = name;
+ rt.remoteLabel = remoteLabel;
+ rt.routedToBluetooth = routedToBluetooth;
+ return rt;
+ }
+ }
+
+ @ProvidesInterface(version = State.VERSION)
+ public static final class State {
+ public static final int VERSION = 1;
+
+ public static int NO_ACTIVE_STREAM = -1;
+
+ public final SparseArray<StreamState> states = new SparseArray<>();
+
+ public int ringerModeInternal;
+ public int ringerModeExternal;
+ public int zenMode;
+ public ComponentName effectsSuppressor;
+ public String effectsSuppressorName;
+ public int activeStream = NO_ACTIVE_STREAM;
+
+ public State copy() {
+ final State rt = new State();
+ for (int i = 0; i < states.size(); i++) {
+ rt.states.put(states.keyAt(i), states.valueAt(i).copy());
+ }
+ rt.ringerModeExternal = ringerModeExternal;
+ rt.ringerModeInternal = ringerModeInternal;
+ rt.zenMode = zenMode;
+ if (effectsSuppressor != null) {
+ rt.effectsSuppressor = effectsSuppressor.clone();
+ }
+ rt.effectsSuppressorName = effectsSuppressorName;
+ rt.activeStream = activeStream;
+ return rt;
+ }
+
+ @Override
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int indent) {
+ final StringBuilder sb = new StringBuilder("{");
+ if (indent > 0) sep(sb, indent);
+ for (int i = 0; i < states.size(); i++) {
+ if (i > 0) {
+ sep(sb, indent);
+ }
+ final int stream = states.keyAt(i);
+ final StreamState ss = states.valueAt(i);
+ sb.append(AudioSystem.streamToString(stream)).append(":").append(ss.level)
+ .append('[').append(ss.levelMin).append("..").append(ss.levelMax)
+ .append(']');
+ if (ss.muted) sb.append(" [MUTED]");
+ if (ss.dynamic) sb.append(" [DYNAMIC]");
+ }
+ sep(sb, indent); sb.append("ringerModeExternal:").append(ringerModeExternal);
+ sep(sb, indent); sb.append("ringerModeInternal:").append(ringerModeInternal);
+ sep(sb, indent); sb.append("zenMode:").append(zenMode);
+ sep(sb, indent); sb.append("effectsSuppressor:").append(effectsSuppressor);
+ sep(sb, indent); sb.append("effectsSuppressorName:").append(effectsSuppressorName);
+ sep(sb, indent); sb.append("activeStream:").append(activeStream);
+ if (indent > 0) sep(sb, indent);
+ return sb.append('}').toString();
+ }
+
+ private static void sep(StringBuilder sb, int indent) {
+ if (indent > 0) {
+ sb.append('\n');
+ for (int i = 0; i < indent; i++) {
+ sb.append(' ');
+ }
+ } else {
+ sb.append(',');
+ }
+ }
+ }
+
+ @ProvidesInterface(version = Callbacks.VERSION)
+ public interface Callbacks {
+ int VERSION = 1;
+
+ void onShowRequested(int reason);
+ void onDismissRequested(int reason);
+ void onStateChanged(State state);
+ void onLayoutDirectionChanged(int layoutDirection);
+ void onConfigurationChanged();
+ void onShowVibrateHint();
+ void onShowSilentHint();
+ void onScreenOff();
+ void onShowSafetyWarning(int flags);
+ void onAccessibilityModeChanged(Boolean showA11yStream);
+ }
+}
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
index 6415ecb44c2e..8e933445be0b 100644
--- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -18,7 +18,7 @@ Copyright (C) 2014 The Android Open Source Project
android:height="48.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="?android:attr/colorForeground">
<group
android:scaleX="1.2"
android:scaleY="1.2"
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index fc1271cf74b6..e3063c5915a9 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -85,6 +85,7 @@
android:layout_height="@dimen/keyguard_affordance_height"
android:layout_gravity="bottom|center_horizontal"
android:src="@drawable/ic_lock_24dp"
+ android:contentDescription="@string/accessibility_unlock_button"
android:scaleType="center" />
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8dc694cc6e47..fec3702145aa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -221,8 +221,8 @@
<string name="accessibility_voice_assist_button">Voice Assist</string>
<!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_button">Unlock</string>
- <!-- Content description of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_fingerprint">Unlock button, waiting for fingerprint</string>
+ <!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
@@ -1382,11 +1382,15 @@
of notifications. Replaces the channel name and only appears when there is more than one channel. -->
<string name="notification_num_channels"> <xliff:g id="number">%d</xliff:g> notification categories</string>
+ <!-- Notification: Control panel: Label that shows when an app has not upgraded to use channels.
+ Hints that the user's only option is to block all of the app's notifications. -->
+ <string name="notification_default_channel_desc">This app doesn\'t have notification categories</string>
+
<!-- Notification: Control panel: Label that shows how many channels this application has
- defined, describing the current notification channel as "1 out of n categories from this app". -->
+ defined, describing the current notification channel as "1 out of n notification categories from this app". -->
<plurals name="notification_num_channels_desc">
- <item quantity="one">1 out of <xliff:g id="number">%d</xliff:g> category from this app</item>
- <item quantity="other">1 out of <xliff:g id="number">%d</xliff:g> categories from this app</item>
+ <item quantity="one">1 out of <xliff:g id="number">%d</xliff:g> notification category from this app</item>
+ <item quantity="other">1 out of <xliff:g id="number">%d</xliff:g> notification categories from this app</item>
</plurals>
<!-- Notification: Control panel: For bundles of notifications, this label that lists the
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 374086d696e6..d058e7837423 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -32,6 +32,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.PluginManagerImpl;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -79,6 +80,7 @@ import com.android.systemui.tuner.TunerServiceImpl;
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
+import com.android.systemui.volume.VolumeDialogControllerImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -252,6 +254,9 @@ public class Dependency extends SystemUI {
mProviders.put(LocalBluetoothManager.class, () ->
LocalBluetoothManager.getInstance(mContext, null));
+ mProviders.put(VolumeDialogController.class, () ->
+ new VolumeDialogControllerImpl(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index af7e9b4e45a8..523724499d96 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import android.content.ComponentName;
import android.content.Context;
import android.util.ArrayMap;
import android.util.Log;
@@ -39,7 +38,7 @@ import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.volume.VolumeDialogController;
+import com.android.systemui.volume.VolumeDialogControllerImpl;
/**
* Class factory to provide customizable SystemUI components.
@@ -89,11 +88,6 @@ public class SystemUIFactory {
return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim);
}
- public VolumeDialogController createVolumeDialogController(Context context,
- ComponentName name) {
- return new VolumeDialogController(context, name);
- }
-
public NotificationIconAreaController createNotificationIconAreaController(Context context,
StatusBar statusBar) {
return new NotificationIconAreaController(context, statusBar);
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
index 67aa4dc1630a..5a19e7dc60ed 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
@@ -15,11 +15,12 @@
*/
package com.android.systemui.car;
-import android.content.ComponentName;
import android.content.Context;
+import android.util.ArrayMap;
+import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.SystemUIFactory;
-import com.android.systemui.volume.VolumeDialogController;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.volume.car.CarVolumeDialogController;
/**
@@ -27,8 +28,9 @@ import com.android.systemui.volume.car.CarVolumeDialogController;
*/
public class CarSystemUIFactory extends SystemUIFactory {
@Override
- public VolumeDialogController createVolumeDialogController(Context context,
- ComponentName name) {
- return new CarVolumeDialogController(context, name);
+ public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
+ Context context) {
+ super.injectDependencies(providers, context);
+ providers.put(VolumeDialogController.class, () -> new CarVolumeDialogController(context));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 1fb6c8704587..ec5f9e7eb6f5 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -59,7 +59,6 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private static PluginManager sInstance;
- private final HandlerThread mBackgroundThread;
private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
= new ArrayMap<>();
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
@@ -71,6 +70,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private ClassLoaderFilter mParentClassLoader;
private boolean mListening;
private boolean mHasOneShot;
+ private Looper mLooper;
public PluginManagerImpl(Context context) {
this(context, new PluginInstanceManagerFactory(),
@@ -82,8 +82,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
UncaughtExceptionHandler defaultHandler) {
mContext = context;
mFactory = factory;
- mBackgroundThread = new HandlerThread("Plugins");
- mBackgroundThread.start();
+ mLooper = Dependency.get(Dependency.BG_LOOPER);
isDebuggable = debuggable;
mPluginPrefs = new PluginPrefs(mContext);
@@ -91,7 +90,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
defaultHandler);
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
if (isDebuggable) {
- new Handler(mBackgroundThread.getLooper()).post(() -> {
+ new Handler(mLooper).post(() -> {
// Plugin dependencies that don't have another good home can go here, but
// dependencies that have better places to init can happen elsewhere.
Dependency.get(PluginDependencyProvider.class)
@@ -120,7 +119,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
throw new RuntimeException("Must be called from UI thread");
}
PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
- false, mBackgroundThread.getLooper(), cls, this);
+ false, mLooper, cls, this);
mPluginPrefs.addAction(action);
PluginInfo<T> info = p.getPlugin();
if (info != null) {
@@ -154,7 +153,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
}
mPluginPrefs.addAction(action);
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
- allowMultiple, mBackgroundThread.getLooper(), cls, this);
+ allowMultiple, mLooper, cls, this);
p.loadAll();
mPluginMap.put(listener, p);
startListening();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 25eea951c585..9b75f0103cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -32,7 +32,6 @@ import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.KeyguardManager;
-import android.app.UiModeManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -42,7 +41,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -298,15 +296,9 @@ public class SystemServicesProxy {
mDummyIcon.eraseColor(0xFF999999);
}
- UiModeManager uiModeManager = (UiModeManager) context.
- getSystemService(Context.UI_MODE_SERVICE);
- if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
- Collections.addAll(sRecentsBlacklist,
- res.getStringArray(R.array.recents_tv_blacklist_array));
- } else {
- Collections.addAll(sRecentsBlacklist,
- res.getStringArray(R.array.recents_blacklist_array));
- }
+ Collections.addAll(sRecentsBlacklist,
+ res.getStringArray(R.array.recents_blacklist_array));
+
mLauncherIcons = new LauncherIcons(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index a9043e4c83bb..54921a7108c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -99,11 +99,14 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
mINotificationManager = iNotificationManager;
mPkg = pkg;
mNotificationChannels = notificationChannels;
+ boolean isSingleDefaultChannel = false;
if (mNotificationChannels.isEmpty()) {
throw new IllegalArgumentException("bindNotification requires at least one channel");
} else if (mNotificationChannels.size() == 1) {
mSingleNotificationChannel = mNotificationChannels.get(0);
mStartingUserImportance = mSingleNotificationChannel.getImportance();
+ isSingleDefaultChannel = mSingleNotificationChannel.getId()
+ .equals(NotificationChannel.DEFAULT_CHANNEL_ID);
} else {
mSingleNotificationChannel = null;
}
@@ -135,24 +138,30 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
String channelsDescText;
mNumChannelsView = (TextView) (findViewById(R.id.num_channels_desc));
- switch (mNotificationChannels.size()) {
- case 1:
- channelsDescText = String.format(mContext.getResources().getQuantityString(
- R.plurals.notification_num_channels_desc, numChannels), numChannels);
- break;
- case 2:
- channelsDescText = mContext.getString(R.string.notification_channels_list_desc_2,
- mNotificationChannels.get(0).getName(),
- mNotificationChannels.get(1).getName());
- break;
- default:
- final int numOthers = mNotificationChannels.size() - 2;
- channelsDescText = String.format(
- mContext.getResources().getQuantityString(
- R.plurals.notification_channels_list_desc_2_and_others, numOthers),
- mNotificationChannels.get(0).getName(),
- mNotificationChannels.get(1).getName(),
- numOthers);
+ if (isSingleDefaultChannel) {
+ channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
+ } else {
+ switch (mNotificationChannels.size()) {
+ case 1:
+ channelsDescText = String.format(mContext.getResources().getQuantityString(
+ R.plurals.notification_num_channels_desc, numChannels), numChannels);
+ break;
+ case 2:
+ channelsDescText = mContext.getString(
+ R.string.notification_channels_list_desc_2,
+ mNotificationChannels.get(0).getName(),
+ mNotificationChannels.get(1).getName());
+ break;
+ default:
+ final int numOthers = mNotificationChannels.size() - 2;
+ channelsDescText = String.format(
+ mContext.getResources().getQuantityString(
+ R.plurals.notification_channels_list_desc_2_and_others,
+ numOthers),
+ mNotificationChannels.get(0).getName(),
+ mNotificationChannels.get(1).getName(),
+ numOthers);
+ }
}
mNumChannelsView.setText(channelsDescText);
@@ -160,9 +169,8 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
// Multiple channels don't use a channel name for the title.
channelNameText = mContext.getString(R.string.notification_num_channels,
mNotificationChannels.size());
- } else if (mSingleNotificationChannel.getId()
- .equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- // If this is the placeholder channel, don't use our channel-specific text.
+ } else if (isSingleDefaultChannel) {
+ // If this is the default channel, don't use our channel-specific text.
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
channelNameText = mSingleNotificationChannel.getName();
@@ -282,15 +290,9 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
}
private void updateSecondaryText() {
- final boolean defaultChannel = mSingleNotificationChannel != null &&
- mSingleNotificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID);
final boolean disabled = mSingleNotificationChannel != null &&
getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
- if (defaultChannel) {
- // Don't show any secondary text if this is from the default channel.
- mChannelDisabledView.setVisibility(View.GONE);
- mNumChannelsView.setVisibility(View.GONE);
- } else if (disabled) {
+ if (disabled) {
mChannelDisabledView.setVisibility(View.VISIBLE);
mNumChannelsView.setVisibility(View.GONE);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index ef42b2f43287..bccc5d5d5fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -179,10 +179,6 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
setRestingAlpha(
anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
setImageDrawable(icon);
- String contentDescription = getResources().getString(anyFingerprintIcon
- ? R.string.accessibility_unlock_button_fingerprint
- : R.string.accessibility_unlock_button);
- setContentDescription(contentDescription);
mHasFingerPrintIcon = anyFingerprintIcon;
if (animation != null && isAnim) {
animation.forceAnimationOnUI();
@@ -225,13 +221,13 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (mHasFingerPrintIcon) {
- // Avoid that the button description is also spoken
- info.setClassName(LockIcon.class.getName());
AccessibilityNodeInfo.AccessibilityAction unlock
= new AccessibilityNodeInfo.AccessibilityAction(
AccessibilityNodeInfo.ACTION_CLICK,
getContext().getString(R.string.accessibility_unlock_without_fingerprint));
info.addAction(unlock);
+ info.setHintText(getContext().getString(
+ R.string.accessibility_waiting_for_fingerprint));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index ca53bc4f7928..8ed4fcac63b0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -24,7 +24,7 @@ import android.util.Log;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.volume.VolumeDialogController.State;
+import com.android.systemui.plugins.VolumeDialogController.State;
import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 9d0ecec43b30..2f9bcff3f8b3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -24,13 +24,19 @@ import android.media.VolumePolicy;
import android.os.Bundle;
import android.os.Handler;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.PluginDependency;
+import com.android.systemui.plugins.PluginDependencyProvider;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.VolumeDialog;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -41,7 +47,7 @@ import java.io.PrintWriter;
* Implementation of VolumeComponent backed by the new volume dialog.
*/
public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable,
- VolumeDialogController.UserActivityListener{
+ VolumeDialogControllerImpl.UserActivityListener{
public static final String VOLUME_DOWN_SILENT = "sysui_volume_down_silent";
public static final String VOLUME_UP_SILENT = "sysui_volume_up_silent";
@@ -53,9 +59,8 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final SystemUI mSysui;
private final Context mContext;
- private final VolumeDialogController mController;
- private final ZenModeController mZenModeController;
- private final VolumeDialog mDialog;
+ private final VolumeDialogControllerImpl mController;
+ private VolumeDialog mDialog;
private VolumePolicy mVolumePolicy = new VolumePolicy(
DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT, // volumeDownToEnterSilent
DEFAULT_VOLUME_UP_TO_EXIT_SILENT, // volumeUpToExitSilent
@@ -66,16 +71,35 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler) {
mSysui = sysui;
mContext = context;
- mController = SystemUIFactory.getInstance().createVolumeDialogController(context, null);
+ mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
mController.setUserActivityListener(this);
- mZenModeController = Dependency.get(ZenModeController.class);
- mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY,
- mController, mZenModeController, mVolumeDialogCallback);
+ // Allow plugins to reference the VolumeDialogController.
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(VolumeDialogController.class);
+ Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
+ .withPlugin(VolumeDialog.class)
+ .withDefault(this::createDefault)
+ .withCallback(dialog -> {
+ if (mDialog != null) {
+ mDialog.destroy();
+ }
+ mDialog = dialog;
+ mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
+ }).build();
applyConfiguration();
Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
VOLUME_SILENT_DO_NOT_DISTURB);
}
+ private VolumeDialog createDefault() {
+ VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
+ impl.setStreamImportant(AudioManager.STREAM_ALARM, true);
+ impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
+ impl.setAutomute(true);
+ impl.setSilentMode(false);
+ return impl;
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (VOLUME_DOWN_SILENT.equals(key)) {
@@ -118,10 +142,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
}
private void applyConfiguration() {
- mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true);
- mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
- mDialog.setAutomute(true);
- mDialog.setSilentMode(false);
mController.setVolumePolicy(mVolumePolicy);
mController.showDndTile(true);
}
@@ -149,8 +169,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mController.dump(fd, pw, args);
- mDialog.dump(pw);
}
private void startSettings(Intent intent) {
@@ -158,7 +176,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
true /* onlyProvisioned */, true /* dismissShade */);
}
- private final VolumeDialog.Callback mVolumeDialogCallback = new VolumeDialog.Callback() {
+ private final VolumeDialogImpl.Callback mVolumeDialogCallback = new VolumeDialogImpl.Callback() {
@Override
public void onZenSettingsClicked() {
startSettings(ZenModePanel.ZEN_SETTINGS);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 276b7c376867..5d51a33c6307 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -16,7 +16,6 @@
package com.android.systemui.volume;
-import android.annotation.IntegerRes;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -44,10 +43,11 @@ import android.provider.Settings;
import android.service.notification.Condition;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
import java.io.FileDescriptor;
@@ -63,8 +63,8 @@ import java.util.Objects;
*
* Methods ending in "W" must be called on the worker thread.
*/
-public class VolumeDialogController {
- private static final String TAG = Util.logTag(VolumeDialogController.class);
+public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
+ private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
private static final int DYNAMIC_STREAM_START_INDEX = 100;
private static final int VIBRATE_HINT_DURATION = 50;
@@ -89,7 +89,6 @@ public class VolumeDialogController {
private final Context mContext;
private AudioManager mAudio;
private final NotificationManager mNoMan;
- private final ComponentName mComponent;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
private final MediaSessions mMediaSessions;
@@ -108,11 +107,10 @@ public class VolumeDialogController {
protected final VC mVolumeController = new VC();
- public VolumeDialogController(Context context, ComponentName component) {
+ public VolumeDialogControllerImpl(Context context) {
mContext = context.getApplicationContext();
Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
- mComponent = component;
- mWorkerThread = new HandlerThread(VolumeDialogController.class.getSimpleName());
+ mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
mWorkerThread.start();
mWorker = new W(mWorkerThread.getLooper());
mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
@@ -197,7 +195,7 @@ public class VolumeDialogController {
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(VolumeDialogController.class.getSimpleName() + " state:");
+ pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
pw.print(" mDestroyed: "); pw.println(mDestroyed);
pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
pw.print(" mState: "); pw.println(mState.toString(4));
@@ -530,7 +528,7 @@ public class VolumeDialogController {
}
private final class VC extends IVolumeController.Stub {
- private final String TAG = VolumeDialogController.TAG + ".VC";
+ private final String TAG = VolumeDialogControllerImpl.TAG + ".VC";
@Override
public void displaySafeVolumeWarning(int flags) throws RemoteException {
@@ -958,113 +956,6 @@ public class VolumeDialogController {
}
}
- public static final class StreamState {
- public boolean dynamic;
- public int level;
- public int levelMin;
- public int levelMax;
- public boolean muted;
- public boolean muteSupported;
- public @IntegerRes int name;
- public String remoteLabel;
- public boolean routedToBluetooth;
-
- public StreamState copy() {
- final StreamState rt = new StreamState();
- rt.dynamic = dynamic;
- rt.level = level;
- rt.levelMin = levelMin;
- rt.levelMax = levelMax;
- rt.muted = muted;
- rt.muteSupported = muteSupported;
- rt.name = name;
- rt.remoteLabel = remoteLabel;
- rt.routedToBluetooth = routedToBluetooth;
- return rt;
- }
- }
-
- public static final class State {
- public static int NO_ACTIVE_STREAM = -1;
-
- public final SparseArray<StreamState> states = new SparseArray<StreamState>();
-
- public int ringerModeInternal;
- public int ringerModeExternal;
- public int zenMode;
- public ComponentName effectsSuppressor;
- public String effectsSuppressorName;
- public int activeStream = NO_ACTIVE_STREAM;
-
- public State copy() {
- final State rt = new State();
- for (int i = 0; i < states.size(); i++) {
- rt.states.put(states.keyAt(i), states.valueAt(i).copy());
- }
- rt.ringerModeExternal = ringerModeExternal;
- rt.ringerModeInternal = ringerModeInternal;
- rt.zenMode = zenMode;
- if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone();
- rt.effectsSuppressorName = effectsSuppressorName;
- rt.activeStream = activeStream;
- return rt;
- }
-
- @Override
- public String toString() {
- return toString(0);
- }
-
- public String toString(int indent) {
- final StringBuilder sb = new StringBuilder("{");
- if (indent > 0) sep(sb, indent);
- for (int i = 0; i < states.size(); i++) {
- if (i > 0) {
- sep(sb, indent);
- }
- final int stream = states.keyAt(i);
- final StreamState ss = states.valueAt(i);
- sb.append(AudioSystem.streamToString(stream)).append(":").append(ss.level)
- .append('[').append(ss.levelMin).append("..").append(ss.levelMax)
- .append(']');
- if (ss.muted) sb.append(" [MUTED]");
- if (ss.dynamic) sb.append(" [DYNAMIC]");
- }
- sep(sb, indent); sb.append("ringerModeExternal:").append(ringerModeExternal);
- sep(sb, indent); sb.append("ringerModeInternal:").append(ringerModeInternal);
- sep(sb, indent); sb.append("zenMode:").append(zenMode);
- sep(sb, indent); sb.append("effectsSuppressor:").append(effectsSuppressor);
- sep(sb, indent); sb.append("effectsSuppressorName:").append(effectsSuppressorName);
- sep(sb, indent); sb.append("activeStream:").append(activeStream);
- if (indent > 0) sep(sb, indent);
- return sb.append('}').toString();
- }
-
- private static void sep(StringBuilder sb, int indent) {
- if (indent > 0) {
- sb.append('\n');
- for (int i = 0; i < indent; i++) {
- sb.append(' ');
- }
- } else {
- sb.append(',');
- }
- }
- }
-
- public interface Callbacks {
- void onShowRequested(int reason);
- void onDismissRequested(int reason);
- void onStateChanged(State state);
- void onLayoutDirectionChanged(int layoutDirection);
- void onConfigurationChanged();
- void onShowVibrateHint();
- void onShowSilentHint();
- void onScreenOff();
- void onShowSafetyWarning(int flags);
- void onAccessibilityModeChanged(Boolean showA11yStream);
- }
-
public interface UserActivityListener {
void onUserActivity();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 1933349abb00..697cac99f244 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -16,6 +16,9 @@
package com.android.systemui.volume;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
@@ -72,28 +75,27 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.VolumeDialogController.State;
+import com.android.systemui.plugins.VolumeDialogController.StreamState;
+import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerZenModePanel;
-import com.android.systemui.volume.VolumeDialogController.State;
-import com.android.systemui.volume.VolumeDialogController.StreamState;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-
/**
* Visual presentation of the volume dialog.
*
- * A client of VolumeDialogController and its state model.
+ * A client of VolumeDialogControllerImpl and its state model.
*
* Methods ending in "H" must be called on the (ui) handler.
*/
-public class VolumeDialog implements TunerService.Tunable {
- private static final String TAG = Util.logTag(VolumeDialog.class);
+public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
+ private static final String TAG = Util.logTag(VolumeDialogImpl.class);
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
@@ -102,7 +104,7 @@ public class VolumeDialog implements TunerService.Tunable {
private final Context mContext;
private final H mHandler = new H();
- private final VolumeDialogController mController;
+ private VolumeDialogController mController;
private Window mWindow;
private CustomDialog mDialog;
@@ -123,7 +125,7 @@ public class VolumeDialog implements TunerService.Tunable {
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
private VolumeDialogMotion mMotion;
- private final int mWindowType;
+ private int mWindowType;
private final ZenModeController mZenModeController;
private boolean mShowing;
@@ -146,32 +148,39 @@ public class VolumeDialog implements TunerService.Tunable {
private boolean mShowFullZen;
private TunerZenModePanel mZenPanel;
- public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
- ZenModeController zenModeController, Callback callback) {
+ public VolumeDialogImpl(Context context) {
mContext = context;
- mController = controller;
- mCallback = callback;
- mWindowType = windowType;
- mZenModeController = zenModeController;
- mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mZenModeController = Dependency.get(ZenModeController.class);
+ mController = Dependency.get(VolumeDialogController.class);
+ mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAccessibilityMgr =
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+ }
+
+ public void init(int windowType, Callback callback) {
+ mCallback = callback;
+ mWindowType = windowType;
initDialog();
mAccessibility.init();
- controller.addCallback(mControllerCallbackH, mHandler);
- controller.getState();
+ mController.addCallback(mControllerCallbackH, mHandler);
+ mController.getState();
Dependency.get(TunerService.class).addTunable(this, SHOW_FULL_ZEN);
final Configuration currentConfig = mContext.getResources().getConfiguration();
mDensity = currentConfig.densityDpi;
}
+ @Override
+ public void destroy() {
+ mController.removeCallback(mControllerCallbackH);
+ }
+
private void initDialog() {
mDialog = new CustomDialog(mContext);
@@ -193,7 +202,7 @@ public class VolumeDialog implements TunerService.Tunable {
final WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = mWindowType;
lp.format = PixelFormat.TRANSLUCENT;
- lp.setTitle(VolumeDialog.class.getSimpleName());
+ lp.setTitle(VolumeDialogImpl.class.getSimpleName());
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top);
lp.gravity = Gravity.TOP;
@@ -361,7 +370,7 @@ public class VolumeDialog implements TunerService.Tunable {
}
public void dump(PrintWriter writer) {
- writer.println(VolumeDialog.class.getSimpleName() + " state:");
+ writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
writer.print(" mExpanded: "); writer.println(mExpanded);
writer.print(" mExpandButtonAnimationRunning: ");
@@ -459,10 +468,6 @@ public class VolumeDialog implements TunerService.Tunable {
}
}
- public void destroy() {
- mController.removeCallback(mControllerCallbackH);
- }
-
public void show(int reason) {
mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
}
@@ -1289,9 +1294,4 @@ public class VolumeDialog implements TunerService.Tunable {
private int animTargetProgress;
private int lastAudibleLevel = 1;
}
-
- public interface Callback {
- void onZenSettingsClicked();
- void onZenPrioritySettingsClicked();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
index a2c32b7e83ad..d28e42e61f29 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
@@ -25,7 +25,7 @@ import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
-import com.android.systemui.volume.VolumeDialogController;
+import com.android.systemui.volume.VolumeDialogControllerImpl;
/**
* A volume dialog controller for the automotive use case.
@@ -33,7 +33,7 @@ import com.android.systemui.volume.VolumeDialogController;
* {@link android.car.media.CarAudioManager} is the source of truth to get the stream volumes.
* And volume changes should be sent to the car's audio module instead of the android's audio mixer.
*/
-public class CarVolumeDialogController extends VolumeDialogController {
+public class CarVolumeDialogController extends VolumeDialogControllerImpl {
private static final String TAG = "CarVolumeDialogController";
private final Car mCar;
@@ -57,8 +57,8 @@ public class CarVolumeDialogController extends VolumeDialogController {
}
};
- public CarVolumeDialogController(Context context, ComponentName component) {
- super(context, component);
+ public CarVolumeDialogController(Context context) {
+ super(context);
mCar = Car.createCar(context, mConnection);
mCar.connect();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index a3d5d5fc3871..b8e9fcd29096 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -29,13 +29,18 @@ import android.net.Uri;
import android.support.test.annotation.UiThreadTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +50,8 @@ import org.mockito.Mockito;
import java.lang.Thread.UncaughtExceptionHandler;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class PluginManagerTest extends SysuiTestCase {
private PluginInstanceManagerFactory mMockFactory;
@@ -59,6 +65,8 @@ public class PluginManagerTest extends SysuiTestCase {
@Before
public void setup() throws Exception {
+ mDependency.injectTestDependency(Dependency.BG_LOOPER,
+ TestableLooper.get(this).getLooper());
mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
mMockFactory = mock(PluginInstanceManagerFactory.class);
@@ -72,7 +80,7 @@ public class PluginManagerTest extends SysuiTestCase {
mMockListener = mock(PluginListener.class);
}
- @UiThreadTest
+ @RunWithLooper(setAsMainLooper = true)
@Test
public void testOneShot() {
Plugin mockPlugin = mock(Plugin.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 8aca546b2730..5632b719df23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -260,12 +260,14 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_NumChannelsTextHiddenWhenDefaultChannel() throws Exception {
+ public void testBindNotification_NumChannelsTextUniqueWhenDefaultChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
- assertTrue(numChannelsView.getVisibility() != View.VISIBLE);
+ assertEquals(View.VISIBLE, numChannelsView.getVisibility());
+ assertEquals(mContext.getString(R.string.notification_default_channel_desc),
+ numChannelsView.getText());
}
@Test
@@ -390,13 +392,14 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
@UiThreadTest
- public void testBindNotification_ChannelDisabledTextHiddenWhenDefaultChannel()
+ public void testBindNotification_ChannelDisabledTextShowsForDefaultChannel()
throws Exception {
+ mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), null, null, null);
final TextView channelDisabledView =
(TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
- assertTrue(channelDisabledView.getVisibility() != View.VISIBLE);
+ assertEquals(View.VISIBLE, channelDisabledView.getVisibility());
}
@Test
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index fb714b9b191a..57d25819654f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3780,6 +3780,9 @@ message MetricsEvent {
// meta-event: a reader has checkpointed the log here.
METRICS_CHECKPOINT = 920;
+ // OPEN: Settings -> Display -> When in VR Mode
+ VR_DISPLAY_PREFERENCE = 921;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 776fa1e58db8..375a72607aa5 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -18,6 +18,8 @@ package com.android.server.autofill.ui;
import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN;
import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN;
+import static com.android.server.autofill.ui.Helper.DEBUG;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -160,7 +162,11 @@ public final class AutoFillUI {
*/
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
@NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) {
- LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
+ if (DEBUG) {
+ Slog.d(TAG, "showFillUi(): id=" + focusedId + ", bounds=" + anchorBounds + " filter="
+ + filterText);
+ }
+ final LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
.setPackageName(packageName)
.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
filterText == null ? 0 : filterText.length())
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 99014a5432b6..98a02f2aa0ca 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -326,6 +326,16 @@ final class FillUi {
}
public void show(int desiredWidth, int desiredHeight, Rect anchorBounds) {
+ try {
+ // TODO: temporary workaround to avoud system_server crashes.
+ unsafelyShow(desiredWidth, desiredHeight, anchorBounds);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error showing Anchored window: w=" + desiredWidth + ", h="
+ + desiredHeight + ", b=" + anchorBounds, e);
+ }
+ }
+
+ private void unsafelyShow(int desiredWidth, int desiredHeight, Rect anchorBounds) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.setTitle("FillUi");
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8e6310fdacbb..891a13bc6878 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -97,6 +97,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.os.AppFuseMount;
+import com.android.internal.os.FuseAppLoop;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
@@ -350,7 +351,7 @@ class StorageManagerService extends IStorageManager.Stub
private int mNextAppFuseName = 0;
@GuardedBy("mAppFuseLock")
- private final SparseArray<Integer> mAppFusePids = new SparseArray<>();
+ private AppFuseBridge mAppFuseBridge = null;
private VolumeInfo findVolumeByIdOrThrow(String id) {
synchronized (mLock) {
@@ -2991,124 +2992,79 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- class CloseableHolder<T extends AutoCloseable> implements AutoCloseable {
- @Nullable T mCloseable;
-
- CloseableHolder(T closeable) {
- mCloseable = closeable;
- }
-
- @Nullable T get() {
- return mCloseable;
- }
-
- @Nullable T release() {
- final T result = mCloseable;
- mCloseable = null;
- return result;
- }
-
- @Override
- public void close() {
- if (mCloseable != null) {
- IoUtils.closeQuietly(mCloseable);
- }
+ private ParcelFileDescriptor mountAppFuse(int uid, int mountId)
+ throws NativeDaemonConnectorException {
+ final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute(
+ "appfuse", "mount", uid, Process.myPid(), mountId);
+ if (event.getFileDescriptors() == null ||
+ event.getFileDescriptors().length == 0) {
+ throw new NativeDaemonConnectorException("Cannot obtain device FD");
}
+ return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
}
- class AppFuseMountScope implements AppFuseBridge.IMountScope {
- final int mUid;
- final int mName;
- final ParcelFileDescriptor mDeviceFd;
-
- AppFuseMountScope(int uid, int pid, int name) throws NativeDaemonConnectorException {
- final NativeDaemonEvent event = mConnector.execute(
- "appfuse", "mount", uid, Process.myPid(), name);
- mUid = uid;
- mName = name;
- synchronized (mLock) {
- mAppFusePids.put(name, pid);
- }
- if (event.getFileDescriptors() != null &&
- event.getFileDescriptors().length > 0) {
- mDeviceFd = new ParcelFileDescriptor(event.getFileDescriptors()[0]);
- } else {
- mDeviceFd = null;
- }
- }
-
- @Override
- public void close() throws NativeDaemonConnectorException {
- try {
- IoUtils.closeQuietly(mDeviceFd);
- mConnector.execute(
- "appfuse", "unmount", mUid, Process.myPid(), mName);
- } finally {
- synchronized (mLock) {
- mAppFusePids.delete(mName);
- }
- }
+ class AppFuseMountScope extends AppFuseBridge.MountScope {
+ public AppFuseMountScope(int uid, int pid, int mountId)
+ throws NativeDaemonConnectorException {
+ super(uid, pid, mountId, mountAppFuse(uid, mountId));
}
@Override
- public ParcelFileDescriptor getDeviceFileDescriptor() {
- return mDeviceFd;
+ public void close() throws Exception {
+ super.close();
+ mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId);
}
}
@Override
public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+ Slog.v(TAG, "mountProxyFileDescriptorBridge");
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
- final int name;
- synchronized (mAppFuseLock) {
- name = mNextAppFuseName++;
- }
- try (CloseableHolder<AppFuseMountScope> mountScope =
- new CloseableHolder<>(new AppFuseMountScope(uid, pid, name))) {
- if (mountScope.get().getDeviceFileDescriptor() == null) {
- throw new RemoteException("Failed to obtain device FD");
- }
- // Create communication channel.
- final ArrayBlockingQueue<Boolean> channel = new ArrayBlockingQueue<>(1);
- final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
- try (CloseableHolder<ParcelFileDescriptor> remote = new CloseableHolder<>(fds[0])) {
- new Thread(
- new AppFuseBridge(mountScope.release(), fds[1], channel),
- AppFuseBridge.TAG).start();
- if (!channel.take()) {
- throw new RemoteException("Failed to init AppFuse mount point");
+ while (true) {
+ synchronized (mAppFuseLock) {
+ boolean newlyCreated = false;
+ if (mAppFuseBridge == null) {
+ mAppFuseBridge = new AppFuseBridge();
+ new Thread(mAppFuseBridge, AppFuseBridge.TAG).start();
+ newlyCreated = true;
+ }
+ try {
+ final int name = mNextAppFuseName++;
+ try {
+ return new AppFuseMount(
+ name,
+ mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
+ } catch (AppFuseBridge.BridgeException e) {
+ if (newlyCreated) {
+ // If newly created bridge fails, it's a real error.
+ throw new RemoteException(e.getMessage());
+ }
+ // It seems the thread of mAppFuseBridge has already been terminated.
+ mAppFuseBridge = null;
+ }
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
}
-
- return new AppFuseMount(name, remote.release());
}
- } catch (NativeDaemonConnectorException e){
- throw e.rethrowAsParcelableException();
- } catch (IOException | InterruptedException error) {
- throw new RemoteException(error.getMessage());
}
}
@Override
- public ParcelFileDescriptor openProxyFileDescriptor(int mountId, int fileId, int mode) {
- final int uid = Binder.getCallingUid();
+ public ParcelFileDescriptor openProxyFileDescriptor(int mountId, int fileId, int mode)
+ throws RemoteException {
+ Slog.v(TAG, "mountProxyFileDescriptorBridge");
final int pid = Binder.getCallingPid();
try {
synchronized (mAppFuseLock) {
- final int expectedPid = mAppFusePids.get(mountId, -1);
- if (expectedPid == -1) {
- Slog.i(TAG, "The mount point has already been unmounted");
- return null;
- }
- if (expectedPid != pid) {
- throw new SecurityException("Mount point was not created by this process.");
+ if (mAppFuseBridge == null) {
+ throw new RemoteException("Cannot find mount point");
}
+ return mAppFuseBridge.openFile(pid, mountId, fileId, mode);
}
- return AppFuseBridge.openFile(uid, mountId, fileId, mode);
- } catch (FileNotFoundException error) {
- Slog.e(TAG, "Failed to openProxyFileDescriptor", error);
- return null;
+ } catch (FileNotFoundException | SecurityException | InterruptedException error) {
+ throw new RemoteException(error.getMessage());
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 8a4f3f76c0ab..fc45344b2f4d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -322,6 +322,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private INotificationManager mNotifManager;
private PowerManagerInternal mPowerManagerInternal;
private IDeviceIdleController mDeviceIdleController;
+ @GuardedBy("mUidRulesFirstLock")
+ private PowerSaveState mRestrictBackgroundPowerState;
+
+ // Store the status of restrict background before turning on battery saver.
+ // Used to restore mRestrictBackground when battery saver is turned off.
+ private boolean mRestrictBackgroundBeforeBsm;
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
@@ -332,6 +338,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
@GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower;
@GuardedBy("mUidRulesFirstLock") volatile boolean mDeviceIdleMode;
+ // Store whether user flipped restrict background in battery saver mode
+ @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackgroundChangedInBsm;
private final boolean mSuppressDefaultPolicy;
@@ -617,8 +625,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
final boolean enabled = result.batterySaverEnabled;
- if (LOGD) Slog.d(TAG,
- "onLowPowerModeChanged(" + enabled + ")");
+ if (LOGD) {
+ Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
+ }
synchronized (mUidRulesFirstLock) {
if (mRestrictPower != enabled) {
mRestrictPower = enabled;
@@ -626,7 +635,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
}
- });
+ });
mRestrictPower = mPowerManagerInternal.getLowPowerState(
ServiceType.NETWORK_FIREWALL).batterySaverEnabled;
@@ -635,6 +644,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// read policy from disk
readPolicyAL();
+ // Update the restrictBackground if battery saver is turned on
+ mRestrictBackgroundBeforeBsm = mRestrictBackground;
+ mRestrictBackgroundPowerState = mPowerManagerInternal
+ .getLowPowerState(ServiceType.DATA_SAVER);
+ final boolean localRestrictBackground =
+ mRestrictBackgroundPowerState.batterySaverEnabled;
+ if (localRestrictBackground && localRestrictBackground != mRestrictBackground) {
+ mRestrictBackground = localRestrictBackground;
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED,
+ mRestrictBackground ? 1 : 0, 0).sendToTarget();
+ }
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public int getServiceType() {
+ return ServiceType.DATA_SAVER;
+ }
+
+ @Override
+ public void onLowPowerModeChanged(PowerSaveState result) {
+ synchronized (mUidRulesFirstLock) {
+ updateRestrictBackgroundByLowPowerModeUL(result);
+ }
+ }
+ });
+
if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
writePolicyAL();
}
@@ -2159,6 +2194,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+
+ if (mRestrictBackgroundPowerState.globalBatterySaverEnabled) {
+ mRestrictBackgroundChangedInBsm = true;
+ }
synchronized (mNetworkPoliciesSecondLock) {
updateNotificationsNL();
writePolicyAL();
@@ -3645,6 +3684,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mHandler.getLooper().getQueue().addIdleHandler(handler);
}
+ @VisibleForTesting
+ public void updateRestrictBackgroundByLowPowerModeUL(final PowerSaveState result) {
+ mRestrictBackgroundPowerState = result;
+
+ boolean restrictBackground = result.batterySaverEnabled;
+ boolean shouldInvokeRestrictBackground;
+ // store the temporary mRestrictBackgroundChangedInBsm and update it at last
+ boolean localRestrictBgChangedInBsm = mRestrictBackgroundChangedInBsm;
+
+ if (result.globalBatterySaverEnabled) {
+ // Try to turn on restrictBackground if (1) it is off and (2) batter saver need to
+ // turn it on.
+ shouldInvokeRestrictBackground = !mRestrictBackground && result.batterySaverEnabled;
+ mRestrictBackgroundBeforeBsm = mRestrictBackground;
+ localRestrictBgChangedInBsm = false;
+ } else {
+ // Try to restore the restrictBackground if it doesn't change in bsm
+ shouldInvokeRestrictBackground = !mRestrictBackgroundChangedInBsm;
+ restrictBackground = mRestrictBackgroundBeforeBsm;
+ }
+
+ if (shouldInvokeRestrictBackground) {
+ setRestrictBackground(restrictBackground);
+ }
+
+ // Change it at last so setRestrictBackground() won't affect this variable
+ mRestrictBackgroundChangedInBsm = localRestrictBgChangedInBsm;
+ }
+
private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 11cc52df180d..0774779a4cf2 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -583,7 +583,7 @@ abstract public class ManagedServices {
ServiceInfo info = mPm.getServiceInfo(component,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
- if (!mConfig.bindPermission.equals(info.permission)) {
+ if (info == null || !mConfig.bindPermission.equals(info.permission)) {
Slog.w(TAG, "Skipping " + getCaption() + " service " + component
+ ": it does not require the permission " + mConfig.bindPermission);
continue;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d18160ca7b7..ede5a5e8e337 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -179,6 +179,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -3116,8 +3117,19 @@ public class NotificationManagerService extends SystemService {
+ " - notification=" + notification);
return;
}
- throw new IllegalArgumentException("No Channel found for channelId=" + channelId
- + ", notification=" + notification);
+ final String noChannelStr = "No Channel found for "
+ + "pkg=" + pkg
+ + ", channelId=" + channelId
+ + ", opPkg=" + opPkg
+ + ", callingUid=" + callingUid
+ + ", userId=" + userId
+ + ", incomingUserId=" + incomingUserId
+ + ", notificationUid=" + notificationUid
+ + ", notification=" + notification;
+ // STOPSHIP TODO: should throw instead of logging.
+ // throw new IllegalArgumentException(noChannelStr);
+ Log.e(TAG, noChannelStr);
+ return;
}
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
@@ -3640,6 +3652,10 @@ public class NotificationManagerService extends SystemService {
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
effect, record.getAudioAttributes());
return true;
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Error creating vibration waveform with pattern: " +
+ Arrays.toString(vibration));
+ return false;
} finally{
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index db23a6ac8305..342ec4b79fed 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -29,9 +29,10 @@ class GlobalActions implements GlobalActionsListener {
private static final boolean DEBUG = false;
private final Context mContext;
- private final LegacyGlobalActions mLegacyGlobalActions;
private final StatusBarManagerInternal mStatusBarInternal;
private final Handler mHandler;
+ private final WindowManagerFuncs mWindowManagerFuncs;
+ private LegacyGlobalActions mLegacyGlobalActions;
private boolean mKeyguardShowing;
private boolean mDeviceProvisioned;
private boolean mStatusBarConnected;
@@ -40,8 +41,7 @@ class GlobalActions implements GlobalActionsListener {
public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mHandler = new Handler();
- mLegacyGlobalActions = new LegacyGlobalActions(context, windowManagerFuncs,
- this::onGlobalActionsDismissed);
+ mWindowManagerFuncs = windowManagerFuncs;
mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
// Some form factors do not have a status bar.
@@ -50,6 +50,12 @@ class GlobalActions implements GlobalActionsListener {
}
}
+ private void ensureLegacyCreated() {
+ if (mLegacyGlobalActions != null) return;
+ mLegacyGlobalActions = new LegacyGlobalActions(mContext, mWindowManagerFuncs,
+ this::onGlobalActionsDismissed);
+ }
+
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
mKeyguardShowing = keyguardShowing;
@@ -60,6 +66,7 @@ class GlobalActions implements GlobalActionsListener {
mHandler.postDelayed(mShowTimeout, 5000);
} else {
// SysUI isn't alive, show legacy menu.
+ ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
}
}
@@ -83,6 +90,7 @@ class GlobalActions implements GlobalActionsListener {
mStatusBarConnected = connected;
if (mShowing && !mStatusBarConnected) {
// Status bar died but we need to be showing global actions still, show the legacy.
+ ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
}
}
@@ -92,6 +100,7 @@ class GlobalActions implements GlobalActionsListener {
public void run() {
if (DEBUG) Slog.d(TAG, "Global actions timeout");
// We haven't heard from sysui, show the legacy dialog.
+ ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
}
};
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 8d20531a6a17..1781d8c657c3 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -43,7 +43,8 @@ public class BatterySaverPolicy extends ContentObserver {
ServiceType.NETWORK_FIREWALL,
ServiceType.SCREEN_BRIGHTNESS,
ServiceType.SOUND,
- ServiceType.BATTERY_STATS})
+ ServiceType.BATTERY_STATS,
+ ServiceType.DATA_SAVER})
public @interface ServiceType {
int NULL = 0;
int GPS = 1;
@@ -55,6 +56,7 @@ public class BatterySaverPolicy extends ContentObserver {
int SCREEN_BRIGHTNESS = 7;
int SOUND = 8;
int BATTERY_STATS = 9;
+ int DATA_SAVER = 10;
}
private static final String TAG = "BatterySaverPolicy";
@@ -73,6 +75,7 @@ public class BatterySaverPolicy extends ContentObserver {
private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
private static final String KEY_FIREWALL_DISABLED = "firewall_disabled";
private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
+ private static final String KEY_DATASAVER_DISABLED = "datasaver_disabled";
private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
@@ -137,6 +140,14 @@ public class BatterySaverPolicy extends ContentObserver {
private boolean mAdjustBrightnessDisabled;
/**
+ * {@code true} if data saver is disabled in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_DATASAVER_DISABLED
+ */
+ private boolean mDataSaverDisabled;
+
+ /**
* This is the flag to decide the gps mode in battery saver mode.
*
* @see Settings.Global#BATTERY_SAVER_CONSTANTS
@@ -191,6 +202,7 @@ public class BatterySaverPolicy extends ContentObserver {
mFireWallDisabled = mParser.getBoolean(KEY_FIREWALL_DISABLED, false);
mAdjustBrightnessDisabled = mParser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
mAdjustBrightnessFactor = mParser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
+ mDataSaverDisabled = mParser.getBoolean(KEY_DATASAVER_DISABLED, true);
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
@@ -210,7 +222,8 @@ public class BatterySaverPolicy extends ContentObserver {
*/
public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
synchronized (BatterySaverPolicy.this) {
- final PowerSaveState.Builder builder = new PowerSaveState.Builder();
+ final PowerSaveState.Builder builder = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(realMode);
if (!realMode) {
return builder.setBatterySaverEnabled(realMode)
.build();
@@ -236,6 +249,9 @@ public class BatterySaverPolicy extends ContentObserver {
return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
.setBrightnessFactor(mAdjustBrightnessFactor)
.build();
+ case ServiceType.DATA_SAVER:
+ return builder.setBatterySaverEnabled(!mDataSaverDisabled)
+ .build();
case ServiceType.SOUND:
return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
.build();
@@ -262,6 +278,7 @@ public class BatterySaverPolicy extends ContentObserver {
pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
pw.println(" " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
+ pw.println(" " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index 0b80d819fd80..ab9ab6713eea 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.security.keymaster.KeyAttestationPackageInfo;
@@ -45,14 +46,19 @@ public class KeyAttestationApplicationIdProviderService
public KeyAttestationApplicationId getKeyAttestationApplicationId(int uid)
throws RemoteException {
- String[] packageNames = mPackageManager.getPackagesForUid(uid);
- if (packageNames == null) {
- throw new RemoteException("No packages for uid");
+ if (Binder.getCallingUid() != android.os.Process.KEYSTORE_UID) {
+ throw new SecurityException("This service can only be used by Keystore");
}
- int userId = UserHandle.getUserId(uid);
- KeyAttestationPackageInfo[] keyAttestationPackageInfos =
- new KeyAttestationPackageInfo[packageNames.length];
+ KeyAttestationPackageInfo[] keyAttestationPackageInfos = null;
+ final long token = Binder.clearCallingIdentity();
try {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ if (packageNames == null) {
+ throw new RemoteException("No packages for uid");
+ }
+ int userId = UserHandle.getUserId(uid);
+ keyAttestationPackageInfos = new KeyAttestationPackageInfo[packageNames.length];
+
for (int i = 0; i < packageNames.length; ++i) {
PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
PackageManager.GET_SIGNATURES, userId);
@@ -61,6 +67,8 @@ public class KeyAttestationApplicationIdProviderService
}
} catch (NameNotFoundException nnfe) {
throw new RemoteException(nnfe.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
return new KeyAttestationApplicationId(keyAttestationPackageInfos);
}
diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java
index bfeaee6af7c4..2f681a3f568e 100644
--- a/services/core/java/com/android/server/security/KeyChainSystemService.java
+++ b/services/core/java/com/android/server/security/KeyChainSystemService.java
@@ -22,10 +22,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.os.Process;
import android.os.UserHandle;
import android.security.IKeyChainService;
import android.util.Slog;
+import com.android.server.DeviceIdleController;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
/**
@@ -45,6 +48,11 @@ public class KeyChainSystemService extends SystemService {
private static final String TAG = "KeyChainSystemService";
+ /**
+ * Maximum time limit for the KeyChain app to deal with packages being removed.
+ */
+ private static final int KEYCHAIN_IDLE_WHITELIST_DURATION_MS = 30 * 1000;
+
public KeyChainSystemService(final Context context) {
super(context);
}
@@ -77,10 +85,25 @@ public class KeyChainSystemService extends SystemService {
}
intent.setComponent(service);
intent.setAction(broadcastIntent.getAction());
- getContext().startServiceAsUser(intent, UserHandle.of(getSendingUserId()));
+ startServiceInBackgroundAsUser(intent, UserHandle.of(getSendingUserId()));
} catch (RuntimeException e) {
Slog.e(TAG, "Unable to forward package removed broadcast to KeyChain", e);
}
}
};
+
+
+ private void startServiceInBackgroundAsUser(final Intent intent, final UserHandle user) {
+ if (intent.getComponent() == null) {
+ return;
+ }
+
+ final String packageName = intent.getComponent().getPackageName();
+ final DeviceIdleController.LocalService idleController =
+ LocalServices.getService(DeviceIdleController.LocalService.class);
+ idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
+ KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
+
+ getContext().startServiceAsUser(intent, user);
+ }
}
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 5a1f473b5ea2..904d9159e578 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -19,18 +19,20 @@ package com.android.server.storage;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
import java.io.File;
import java.io.FileNotFoundException;
-import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
/**
* Runnable that delegates FUSE command from the kernel to application.
* run() blocks until all opened files on the FUSE mount point are closed. So this should be run in
* a separated thread.
*/
-public class AppFuseBridge implements Runnable, AutoCloseable {
+public class AppFuseBridge implements Runnable {
public static final String TAG = "AppFuseBridge";
/**
@@ -41,71 +43,138 @@ public class AppFuseBridge implements Runnable, AutoCloseable {
*/
private static final String APPFUSE_MOUNT_NAME_TEMPLATE = "/mnt/appfuse/%d_%d";
- private final IMountScope mMountScope;
- private final ParcelFileDescriptor mProxyFd;
- private final BlockingQueue<Boolean> mChannel;
+ @GuardedBy("this")
+ private final SparseArray<MountScope> mScopes = new SparseArray<>();
- /**
- * @param mountScope Listener to unmount mount point.
- * @param proxyFd FD of socket pair. Ownership of FD is taken by AppFuseBridge.
- * @param channel Channel that the runnable send mount result to.
- */
- public AppFuseBridge(
- IMountScope mountScope, ParcelFileDescriptor proxyFd, BlockingQueue<Boolean> channel) {
- Preconditions.checkNotNull(mountScope);
- Preconditions.checkNotNull(proxyFd);
- Preconditions.checkNotNull(channel);
- mMountScope = mountScope;
- mProxyFd = proxyFd;
- mChannel = channel;
+ @GuardedBy("this")
+ private long mNativeLoop;
+
+ public AppFuseBridge() {
+ mNativeLoop = native_new();
}
- @Override
- public void run() {
+ public ParcelFileDescriptor addBridge(MountScope mountScope)
+ throws BridgeException {
try {
- // deviceFd and proxyFd must be closed in native_start_loop.
- native_start_loop(
- mMountScope.getDeviceFileDescriptor().detachFd(),
- mProxyFd.detachFd());
+ synchronized (this) {
+ Preconditions.checkArgument(mScopes.indexOfKey(mountScope.mountId) < 0);
+ if (mNativeLoop == 0) {
+ throw new BridgeException("The thread has already been terminated");
+ }
+ final int fd = native_add_bridge(
+ mNativeLoop, mountScope.mountId, mountScope.deviceFd.detachFd());
+ if (fd == -1) {
+ throw new BridgeException("Failed to invoke native_add_bridge");
+ }
+ final ParcelFileDescriptor result = ParcelFileDescriptor.adoptFd(fd);
+ mScopes.put(mountScope.mountId, mountScope);
+ mountScope = null;
+ return result;
+ }
} finally {
- close();
+ IoUtils.closeQuietly(mountScope);
+ }
+ }
+
+ @Override
+ public void run() {
+ native_start_loop(mNativeLoop);
+ synchronized (this) {
+ native_delete(mNativeLoop);
+ mNativeLoop = 0;
}
}
- public static ParcelFileDescriptor openFile(int uid, int mountId, int fileId, int mode)
- throws FileNotFoundException {
- final File mountPoint = getMountPoint(uid, mountId);
+ public ParcelFileDescriptor openFile(int pid, int mountId, int fileId, int mode)
+ throws FileNotFoundException, SecurityException, InterruptedException {
+ final MountScope scope;
+ synchronized (this) {
+ scope = mScopes.get(mountId);
+ if (scope == null) {
+ throw new FileNotFoundException("Cannot find mount point");
+ }
+ }
+ if (scope.pid != pid) {
+ throw new SecurityException("PID does not match");
+ }
+ final boolean result = scope.waitForMount();
+ if (result == false) {
+ throw new FileNotFoundException("Mount failed");
+ }
try {
- if (Os.stat(mountPoint.getPath()).st_ino != 1) {
+ if (Os.stat(scope.mountPoint.getPath()).st_ino != 1) {
throw new FileNotFoundException("Could not find bridge mount point.");
}
} catch (ErrnoException e) {
throw new FileNotFoundException(
- "Failed to stat mount point: " + mountPoint.getParent());
+ "Failed to stat mount point: " + scope.mountPoint.getParent());
}
- return ParcelFileDescriptor.open(new File(mountPoint, String.valueOf(fileId)), mode);
+ return ParcelFileDescriptor.open(new File(scope.mountPoint, String.valueOf(fileId)), mode);
}
- private static File getMountPoint(int uid, int mountId) {
- return new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE, uid, mountId));
+ // Used by com_android_server_storage_AppFuse.cpp.
+ synchronized private void onMount(int mountId) {
+ final MountScope scope = mScopes.get(mountId);
+ if (scope != null) {
+ scope.setMountResultLocked(true);
+ }
}
- @Override
- public void close() {
- IoUtils.closeQuietly(mMountScope);
- IoUtils.closeQuietly(mProxyFd);
- // Invoke countDown here in case where close is invoked before mount.
- mChannel.offer(false);
+ // Used by com_android_server_storage_AppFuse.cpp.
+ synchronized private void onClosed(int mountId) {
+ final MountScope scope = mScopes.get(mountId);
+ if (scope != null) {
+ scope.setMountResultLocked(false);
+ IoUtils.closeQuietly(scope);
+ mScopes.remove(mountId);
+ }
}
- // Used by com_android_server_storage_AppFuse.cpp.
- private void onMount() {
- mChannel.offer(true);
+ public static class MountScope implements AutoCloseable {
+ public final int uid;
+ public final int pid;
+ public final int mountId;
+ public final ParcelFileDescriptor deviceFd;
+ public final File mountPoint;
+ private final CountDownLatch mMounted = new CountDownLatch(1);
+ private boolean mMountResult = false;
+
+ public MountScope(int uid, int pid, int mountId, ParcelFileDescriptor deviceFd) {
+ this.uid = uid;
+ this.pid = pid;
+ this.mountId = mountId;
+ this.deviceFd = deviceFd;
+ this.mountPoint = new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE, uid, mountId));
+ }
+
+ @GuardedBy("AppFuseBridge.this")
+ void setMountResultLocked(boolean result) {
+ if (mMounted.getCount() == 0) {
+ return;
+ }
+ mMountResult = result;
+ mMounted.countDown();
+ }
+
+ boolean waitForMount() throws InterruptedException {
+ mMounted.await();
+ return mMountResult;
+ }
+
+ @Override
+ public void close() throws Exception {
+ deviceFd.close();
+ }
}
- public static interface IMountScope extends AutoCloseable {
- ParcelFileDescriptor getDeviceFileDescriptor();
+ public static class BridgeException extends Exception {
+ public BridgeException(String message) {
+ super(message);
+ }
}
- private native boolean native_start_loop(int deviceFd, int proxyFd);
+ private native long native_new();
+ private native void native_delete(long loop);
+ private native void native_start_loop(long loop);
+ private native int native_add_bridge(long loop, int mountId, int deviceId);
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index fc377973221b..85eae0212373 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -540,12 +540,14 @@ public class DockedStackDividerController implements DimLayerUser {
checkMinimizeChanged(true /* animate */);
// We were minimized, and now we are still minimized, but somebody is trying to launch an
- // app in docked stack, better show recent apps so we actually get unminimized! This catches
+ // app in docked stack, better show recent apps so we actually get unminimized! However do
+ // not do this if keyguard is dismissed such as when the device is unlocking. This catches
// any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
// we couldn't retrace the launch of the app in the docked stack to the launch from
// homescreen.
if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
- && appTransition != TRANSIT_NONE) {
+ && appTransition != TRANSIT_NONE &&
+ !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
mService.showRecentApps(true /* fromHome */);
}
}
@@ -579,6 +581,12 @@ public class DockedStackDividerController implements DimLayerUser {
if (homeTask == null || !isWithinDisplay(homeTask)) {
return;
}
+
+ // Do not minimize when dock is already minimized while keyguard is showing and not
+ // occluded such as unlocking the screen
+ if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
+ return;
+ }
final TaskStack fullscreenStack =
mDisplayContent.getStackById(FULLSCREEN_WORKSPACE_STACK_ID);
final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
index 2f20ecd1954d..c8f842dde7ae 100644
--- a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -19,16 +19,19 @@
#include <android_runtime/Log.h>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <core_jni_helpers.h>
#include <libappfuse/FuseBridgeLoop.h>
+#include <libappfuse/FuseBuffer.h>
#include <nativehelper/JNIHelp.h>
namespace android {
namespace {
constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge";
-static jclass appFuseClass;
-static jmethodID appFuseOnMount;
+static jclass gAppFuseClass;
+static jmethodID gAppFuseOnMount;
+static jmethodID gAppFuseOnClosed;
class Callback : public fuse::FuseBridgeLoopCallback {
JNIEnv* mEnv;
@@ -36,8 +39,16 @@ class Callback : public fuse::FuseBridgeLoopCallback {
public:
Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
- void OnMount() override {
- mEnv->CallVoidMethod(mSelf, appFuseOnMount);
+ void OnMount(int mount_id) override {
+ mEnv->CallVoidMethod(mSelf, gAppFuseOnMount, mount_id);
+ if (mEnv->ExceptionCheck()) {
+ LOGE_EX(mEnv, nullptr);
+ mEnv->ExceptionClear();
+ }
+ }
+
+ void OnClosed(int mount_id) override {
+ mEnv->CallVoidMethod(mSelf, gAppFuseOnClosed, mount_id);
if (mEnv->ExceptionCheck()) {
LOGE_EX(mEnv, nullptr);
mEnv->ExceptionClear();
@@ -45,17 +56,93 @@ public:
}
};
-jboolean com_android_server_storage_AppFuseBridge_start_loop(
- JNIEnv* env, jobject self, jint devJavaFd, jint proxyJavaFd) {
+class MonitorScope final {
+public:
+ MonitorScope(JNIEnv* env, jobject obj) : mEnv(env), mObj(obj), mLocked(false) {
+ if (mEnv->MonitorEnter(obj) == JNI_OK) {
+ mLocked = true;
+ } else {
+ LOG(ERROR) << "Failed to enter monitor.";
+ }
+ }
+
+ ~MonitorScope() {
+ if (mLocked) {
+ if (mEnv->MonitorExit(mObj) != JNI_OK) {
+ LOG(ERROR) << "Failed to exit monitor.";
+ }
+ }
+ }
+
+ operator bool() {
+ return mLocked;
+ }
+
+private:
+ // Lifetime of |MonitorScope| must be shorter than the reference of mObj.
+ JNIEnv* mEnv;
+ jobject mObj;
+ bool mLocked;
+
+ DISALLOW_COPY_AND_ASSIGN(MonitorScope);
+};
+
+jlong com_android_server_storage_AppFuseBridge_new(JNIEnv* env, jobject self) {
+ return reinterpret_cast<jlong>(new fuse::FuseBridgeLoop());
+}
+
+void com_android_server_storage_AppFuseBridge_delete(JNIEnv* env, jobject self, jlong java_loop) {
+ fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
+ CHECK(loop);
+ delete loop;
+}
+
+void com_android_server_storage_AppFuseBridge_start_loop(
+ JNIEnv* env, jobject self, jlong java_loop) {
+ fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
+ CHECK(loop);
Callback callback(env, self);
- return fuse::StartFuseBridgeLoop(devJavaFd, proxyJavaFd, &callback);
+ loop->Start(&callback);
+}
+
+jint com_android_server_storage_AppFuseBridge_add_bridge(
+ JNIEnv* env, jobject self, jlong java_loop, jint mountId, jint javaDevFd) {
+ base::unique_fd devFd(javaDevFd);
+ fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
+ CHECK(loop);
+
+ base::unique_fd proxyFd[2];
+ if (!fuse::SetupMessageSockets(&proxyFd)) {
+ return -1;
+ }
+
+ if (!loop->AddBridge(mountId, std::move(devFd), std::move(proxyFd[0]))) {
+ return -1;
+ }
+
+ return proxyFd[1].release();
}
const JNINativeMethod methods[] = {
{
+ "native_new",
+ "()J",
+ reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_new)
+ },
+ {
+ "native_delete",
+ "(J)V",
+ reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_delete)
+ },
+ {
"native_start_loop",
- "(II)Z",
- (void *) com_android_server_storage_AppFuseBridge_start_loop
+ "(J)V",
+ reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_start_loop)
+ },
+ {
+ "native_add_bridge",
+ "(JII)I",
+ reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_add_bridge)
}
};
@@ -64,8 +151,9 @@ const JNINativeMethod methods[] = {
void register_android_server_storage_AppFuse(JNIEnv* env) {
CHECK(env != nullptr);
- appFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
- appFuseOnMount = GetMethodIDOrDie(env, appFuseClass, "onMount", "()V");
+ gAppFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+ gAppFuseOnMount = GetMethodIDOrDie(env, gAppFuseClass, "onMount", "(I)V");
+ gAppFuseOnClosed = GetMethodIDOrDie(env, gAppFuseClass, "onClosed", "(I)V");
RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
}
} // namespace android
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index ab83b9d84747..4c23d79cf7ff 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -52,6 +52,7 @@ import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import com.android.server.lights.Light;
@@ -259,6 +260,7 @@ public class NotificationManagerServiceTest {
@Test
@UiThreadTest
+ @Ignore("Flaky")
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), new int[1], 0);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f8d105e5ac31..29c6f89e5fa0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -37,6 +37,7 @@ import static com.android.server.net.NetworkPolicyManagerService.ProcStateSeqHis
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -51,10 +52,15 @@ import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -89,6 +95,7 @@ import android.net.NetworkTemplate;
import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
@@ -198,6 +205,7 @@ public class NetworkPolicyManagerServiceTest {
private IUidObserver mUidObserver;
private INetworkManagementEventObserver mNetworkObserver;
+ private PowerManagerInternal mPowerManagerInternal;
private NetworkPolicyListenerAnswer mPolicyListener;
private NetworkPolicyManagerService mService;
@@ -227,12 +235,16 @@ public class NetworkPolicyManagerServiceTest {
@BeforeClass
public static void registerLocalServices() {
- addLocalServiceMock(PowerManagerInternal.class);
addLocalServiceMock(DeviceIdleController.LocalService.class);
final UsageStatsManagerInternal usageStats =
addLocalServiceMock(UsageStatsManagerInternal.class);
when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{});
mActivityManagerInternal = addLocalServiceMock(ActivityManagerInternal.class);
+
+ final PowerSaveState state = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(false).build();
+ final PowerManagerInternal pmInternal = addLocalServiceMock(PowerManagerInternal.class);
+ when(pmInternal.getLowPowerState(anyInt())).thenReturn(state);
}
@Before
@@ -401,6 +413,85 @@ public class NetworkPolicyManagerServiceTest {
removeRestrictBackgroundWhitelist(false);
}
+ @Test
+ public void testLowPowerModeObserver_ListenersRegistered()
+ throws Exception {
+ PowerManagerInternal pmInternal = LocalServices.getService(PowerManagerInternal.class);
+
+ verify(pmInternal, atLeast(2)).registerLowPowerModeObserver(any());
+ }
+
+ @Test
+ public void updateRestrictBackgroundByLowPowerMode_RestrictOnBeforeBsm_RestrictOnAfterBsm()
+ throws Exception {
+ setRestrictBackground(true);
+ PowerSaveState stateOn = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(true)
+ .setBatterySaverEnabled(false)
+ .build();
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
+
+ // RestrictBackground should be on even though battery saver want to turn it off
+ assertThat(mService.getRestrictBackground()).isTrue();
+
+ PowerSaveState stateOff = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(false)
+ .setBatterySaverEnabled(false)
+ .build();
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+ // RestrictBackground should be on, following its previous state
+ assertThat(mService.getRestrictBackground()).isTrue();
+ }
+
+ @Test
+ public void updateRestrictBackgroundByLowPowerMode_RestrictOffBeforeBsm_RestrictOffAfterBsm()
+ throws Exception {
+ setRestrictBackground(false);
+ PowerSaveState stateOn = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(true)
+ .setBatterySaverEnabled(true)
+ .build();
+
+ doReturn(true).when(mNetworkManager).setDataSaverModeEnabled(true);
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
+
+ // RestrictBackground should be turned on because of battery saver
+ assertThat(mService.getRestrictBackground()).isTrue();
+
+ PowerSaveState stateOff = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(false)
+ .setBatterySaverEnabled(false)
+ .build();
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+ // RestrictBackground should be off, following its previous state
+ assertThat(mService.getRestrictBackground()).isFalse();
+ }
+
+ @Test
+ public void updateRestrictBackgroundByLowPowerMode_StatusChangedInBsm_DoNotRestore()
+ throws Exception {
+ setRestrictBackground(true);
+ PowerSaveState stateOn = new PowerSaveState.Builder()
+ .setGlobalBatterySaverEnabled(true)
+ .setBatterySaverEnabled(true)
+ .build();
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
+
+ // RestrictBackground should still be on
+ assertThat(mService.getRestrictBackground()).isTrue();
+
+ // User turns off RestrictBackground manually
+ setRestrictBackground(false);
+ PowerSaveState stateOff = new PowerSaveState.Builder().setBatterySaverEnabled(
+ false).build();
+ mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+ // RestrictBackground should be off because user changes it manually
+ assertThat(mService.getRestrictBackground()).isFalse();
+ }
+
private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
// Sanity checks.
assertWhitelistUids(UID_A);
@@ -1231,7 +1322,7 @@ public class NetworkPolicyManagerServiceTest {
private void setRestrictBackground(boolean flag) throws Exception {
// Must set expectation, otherwise NMPS will reset value to previous one.
- when(mNetworkManager.setDataSaverModeEnabled(flag)).thenReturn(true);
+ doReturn(true).when(mNetworkManager).setDataSaverModeEnabled(flag);
mService.setRestrictBackground(flag);
// Sanity check.
assertEquals("restrictBackground not set", flag, mService.getRestrictBackground());
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 7282b3ea9d85..69589e7d1f66 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -19,7 +19,9 @@ import android.os.PowerSaveState;
import android.os.Handler;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.server.power.BatterySaverPolicy.ServiceType;
+
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -40,6 +42,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
+ "animation_disabled=false,"
+ "soundtrigger_disabled=true,"
+ "firewall_disabled=false,"
+ + "datasaver_disabled=false,"
+ "adjust_brightness_disabled=true,"
+ "adjust_brightness_factor=0.7,"
+ "fullbackup_deferred=true,"
@@ -99,6 +102,18 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
}
@SmallTest
+ public void testGetBatterySaverPolicy_PolicyDataSaver_DefaultValueCorrect() {
+ mBatterySaverPolicy.updateConstants("");
+ final PowerSaveState batterySaverStateOn =
+ mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
+ assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
+
+ final PowerSaveState batterySaverStateOff = mBatterySaverPolicy.getBatterySaverPolicy(
+ ServiceType.DATA_SAVER, BATTERY_SAVER_OFF);
+ assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+ }
+
+ @SmallTest
public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
testServiceDefaultValue(ServiceType.SCREEN_BRIGHTNESS);
@@ -137,7 +152,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
assertThat(networkState.batterySaverEnabled).isTrue();
final PowerSaveState screenState =
- mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, BATTERY_SAVER_ON);
+ mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
+ BATTERY_SAVER_ON);
assertThat(screenState.batterySaverEnabled).isFalse();
assertThat(screenState.brightnessFactor).isWithin(PRECISION).of(BRIGHTNESS_FACTOR);
@@ -149,6 +165,10 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
ServiceType.KEYVALUE_BACKUP, BATTERY_SAVER_ON);
assertThat(keyValueBackupState.batterySaverEnabled).isFalse();
+ final PowerSaveState dataSaverState = mBatterySaverPolicy.getBatterySaverPolicy(
+ ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
+ assertThat(dataSaverState.batterySaverEnabled).isTrue();
+
final PowerSaveState gpsState =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON);
assertThat(gpsState.batterySaverEnabled).isTrue();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index dd23850c2fca..26c9430408e8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,8 +23,8 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.WorkerThread;
import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.app.PendingIntent;
import android.content.ContentResolver;
@@ -50,6 +50,7 @@ import android.util.Log;
import com.android.ims.internal.IImsServiceController;
import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IPhoneSubInfo;
@@ -940,7 +941,11 @@ public class TelephonyManager {
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
+ * MEID for CDMA.
*/
+ @Deprecated
public String getDeviceId() {
try {
ITelephony telephony = getITelephony();
@@ -962,7 +967,11 @@ public class TelephonyManager {
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param slotIndex of which deviceID is returned
+ *
+ * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
+ * MEID for CDMA.
*/
+ @Deprecated
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
try {
@@ -978,29 +987,25 @@ public class TelephonyManager {
}
/**
- * Returns the IMEI. Return null if IMEI is not available.
+ * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
+ * available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
- * @hide
*/
- @SystemApi
public String getImei() {
return getImei(getDefaultSim());
}
/**
- * Returns the IMEI. Return null if IMEI is not available.
+ * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
+ * available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
- * @param slotIndex of which deviceID is returned
- *
- * @hide
+ * @param slotIndex of which IMEI is returned
*/
- @SystemApi
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1015,6 +1020,37 @@ public class TelephonyManager {
}
/**
+ * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ public String getMeid() {
+ return getMeid(getDefaultSim());
+ }
+
+ /**
+ * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param slotIndex of which MEID is returned
+ */
+ public String getMeid(int slotIndex) {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+
+ try {
+ return telephony.getMeidForSlot(slotIndex, getOpPackageName());
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
+ }
+
+ /**
* Returns the NAI. Return null if NAI is not available.
*
*/
@@ -4056,9 +4092,19 @@ public class TelephonyManager {
return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
}
- /** {@hide} */
+ /**
+ * @return default SIM's slot index. If SIM is not inserted, return default SIM slot index.
+ *
+ * {@hide}
+ */
+ @VisibleForTesting
public int getDefaultSim() {
- return SubscriptionManager.getSlotIndex(SubscriptionManager.getDefaultSubscriptionId());
+ int slotIndex = SubscriptionManager.getSlotIndex(
+ SubscriptionManager.getDefaultSubscriptionId());
+ if (slotIndex == SubscriptionManager.SIM_NOT_INSERTED) {
+ slotIndex = SubscriptionManager.DEFAULT_SIM_SLOT_INDEX;
+ }
+ return slotIndex;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 76138373f457..cd15c444d8bd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1096,6 +1096,16 @@ interface ITelephony {
String getImeiForSlot(int slotIndex, String callingPackage);
/**
+ * Returns the MEID for the given slot.
+ *
+ * @param slotIndex - device slot.
+ * @param callingPackage The package making the call.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ String getMeidForSlot(int slotIndex, String callingPackage);
+
+ /**
* Returns the device software version.
*
* @param slotIndex - device slot.
diff --git a/wifi/java/android/net/wifi/IconInfo.aidl b/wifi/java/android/net/wifi/IconInfo.aidl
deleted file mode 100644
index a7bb2ef8bc3f..000000000000
--- a/wifi/java/android/net/wifi/IconInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * 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.
- */
-
-package android.net.wifi;
-
-parcelable IconInfo;
diff --git a/wifi/java/android/net/wifi/IconInfo.java b/wifi/java/android/net/wifi/IconInfo.java
deleted file mode 100644
index 0eae363861f8..000000000000
--- a/wifi/java/android/net/wifi/IconInfo.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.wifi;
-
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * A class representing icon information.
- */
-public final class IconInfo implements Parcelable {
- /**
- * Name of the icon file.
- */
- private final String mFilename;
-
- /**
- * Raw binary data of the icon.
- */
- private final byte[] mData;
-
- public IconInfo(String filename, byte[] data) {
- mFilename = filename;
- mData = data;
- }
-
- public IconInfo(IconInfo source) {
- if (source == null) {
- mFilename = null;
- mData = null;
- return;
- }
-
- mFilename = source.mFilename;
- if (source.mData != null) {
- mData = Arrays.copyOf(source.mData, source.mData.length);
- } else {
- mData = null;
- }
- }
-
- public String getFilename() {
- return mFilename;
- }
-
- public byte[] getData() {
- return mData;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (!(thatObject instanceof IconInfo)) {
- return false;
- }
- IconInfo that = (IconInfo) thatObject;
- return TextUtils.equals(mFilename, that.mFilename)
- && Arrays.equals(mData, that.mData);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mFilename, mData);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mFilename);
- dest.writeByteArray(mData);
- }
-
- public static final Creator<IconInfo> CREATOR =
- new Creator<IconInfo>() {
- @Override
- public IconInfo createFromParcel(Parcel in) {
- String filename = in.readString();
- byte[] data = in.createByteArray();
- return new IconInfo(filename, data);
- }
-
- @Override
- public IconInfo[] newArray(int size) {
- return new IconInfo[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4f2881b87616..824c436ac9fd 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -120,7 +120,8 @@ public class WifiManager {
*
* Included extras:
* {@link #EXTRA_BSSID_LONG}
- * {@link #EXTRA_ICON_INFO}
+ * {@link #EXTRA_FILENAME}
+ * {@link #EXTRA_ICON}
*
* Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
*
@@ -136,12 +137,18 @@ public class WifiManager {
*/
public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
/**
- * Icon information.
+ * Icon data.
*
* Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
- * {@link IconInfo}.
+ * {@link android.graphics.drawable.Icon}.
*/
- public static final String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+ public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
+ /**
+ * Name of a file.
+ *
+ * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
+ */
+ public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
/**
* Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
@@ -984,9 +991,9 @@ public class WifiManager {
/**
* Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
- * will be broadcasted once the request is completed. The return value of
- * {@link IconInfo#getData} from the intent extra will indicate the result of the request.
- * A value of {@code null} will indicate a failure.
+ * will be broadcasted once the request is completed. The presence of the intent extra
+ * {@link #EXTRA_ICON} will indicate the result of the request.
+ * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
*
* @param bssid The BSSID of the AP
* @param fileName Name of the icon file (remote file) to query from the AP
diff --git a/wifi/tests/src/android/net/wifi/IconInfoTest.java b/wifi/tests/src/android/net/wifi/IconInfoTest.java
deleted file mode 100644
index 2fdb484fce19..000000000000
--- a/wifi/tests/src/android/net/wifi/IconInfoTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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
- */
-
-package android.net.wifi;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.wifi.IconInfo;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link android.net.wifi.IconInfo}.
- */
-@SmallTest
-public class IconInfoTest {
- private static final String TEST_FILENAME = "testIcon";
- private static final byte[] TEST_DATA = new byte[] {0x12, 0x23, 0x34, 0x45, 0x56, 0x67};
-
- /**
- * Verify parcel write and read consistency for the given {@link IconInfo}
- *
- * @param writeIcon the {@link IconInfo} to write and verify
- * @throws Exception
- */
- private static void verifyParcel(IconInfo writeIcon) throws Exception {
- Parcel parcel = Parcel.obtain();
- writeIcon.writeToParcel(parcel, 0);
-
- parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
- IconInfo readIcon = IconInfo.CREATOR.createFromParcel(parcel);
- assertEquals(writeIcon, readIcon);
- }
-
- /**
- * Verify parcel serialization for a {@link IconInfo} with null data.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithNullData() throws Exception {
- verifyParcel(new IconInfo(TEST_FILENAME, (byte[]) null));
- }
-
- /**
- * Verify parcel serialization for a {@link IconInfo} with zero length data.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithZeroLengthData() throws Exception {
- verifyParcel(new IconInfo(TEST_FILENAME, new byte[0]));
- }
-
- /**
- * Verify parcel serialization for a {@link IconInfo} with non-zero length data.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithNonZeroLengthData() throws Exception {
- verifyParcel(new IconInfo(TEST_FILENAME, TEST_DATA));
- }
-
- /**
- * Verify parcel serialization for a {@link IconInfo} with a null filename.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithNullFilename() throws Exception {
- verifyParcel(new IconInfo(null, TEST_DATA));
- }
-
- /**
- * Verify the copy constructor with non-null filename and data.
- *
- * @throws Exception
- */
- @Test
- public void verifyCopyConstructor() throws Exception {
- IconInfo source = new IconInfo(TEST_FILENAME, TEST_DATA);
- assertEquals(source, new IconInfo(source));
- }
-
- /**
- * Verify the copy constructor with null data.
- *
- * @throws Exception
- */
- @Test
- public void verifyCopyConstructorWithNullData() throws Exception {
- IconInfo source = new IconInfo(TEST_FILENAME, (byte[]) null);
- assertEquals(source, new IconInfo(source));
- }
-
- /**
- * Verify the copy constructor with null file name.
- *
- * @throws Exception
- */
- @Test
- public void verifyCopyConstructorWithNullFilename() throws Exception {
- IconInfo source = new IconInfo(null, TEST_DATA);
- assertEquals(source, new IconInfo(source));
- }
-}