Merge "Fix music output unable switch from BTHS to Phone"
diff --git a/Android.bp b/Android.bp
index 4219d36..05c7dbc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -772,7 +772,6 @@
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
"networkstack-aidl-framework-java",
- "netd_aidl_parcelables-java",
"devicepolicyprotosnano",
],
@@ -912,6 +911,9 @@
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
"core/java/android/net/ip/IIpClient.aidl",
"core/java/android/net/ip/IIpClientCallbacks.aidl",
+ "core/java/android/net/IIpMemoryStore.aidl",
+ "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+ "core/java/android/net/ipmemorystore/**/*.aidl",
],
backend: {
ndk: {
@@ -925,12 +927,20 @@
}
aidl_interface {
+ name: "ipmemorystore-aidl-interfaces",
+ local_include_dir: "core/java",
+ srcs: [
+ "core/java/android/net/IIpMemoryStore.aidl",
+ "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+ "core/java/android/net/ipmemorystore/**/*.aidl",
+ ],
+}
+
+aidl_interface {
name: "networkstack-aidl-framework",
local_include_dir: "core/java",
srcs: [
"core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
- "core/java/android/net/IIpMemoryStore.aidl",
- "core/java/android/net/ipmemorystore/**/*.aidl",
],
api_dir: "aidl/networkstack",
backend: {
@@ -941,18 +951,25 @@
}
filegroup {
- name: "framework-networkstack-shared-srcs",
+ name: "framework-annotations",
srcs: [
- // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
- "core/java/android/net/DhcpResults.java",
- "core/java/android/util/LocalLog.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
"core/java/com/android/internal/annotations/VisibleForTesting.java",
+ ]
+}
+
+filegroup {
+ name: "framework-networkstack-shared-srcs",
+ srcs: [
+ // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
+ ":framework-annotations",
+ "core/java/android/net/DhcpResults.java",
+ "core/java/android/util/LocalLog.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
"core/java/com/android/internal/util/IState.java",
@@ -1807,4 +1824,4 @@
name: "framework-aidl-mappings",
srcs: [":framework-defaults"],
output: "framework-aidl-mappings.txt"
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index dcaa28b..79a909d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5429,7 +5429,7 @@
method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
method @NonNull public android.app.Notification.Action build();
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
- method public android.os.Bundle getExtras();
+ method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
@@ -6623,7 +6623,7 @@
method @Nullable public String[] getAccountTypesWithManagementDisabled();
method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
- method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
+ method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6736,7 +6736,7 @@
method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
- method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -12016,7 +12016,7 @@
method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]);
method @NonNull public android.content.pm.ShortcutInfo.Builder setLocusId(@NonNull android.content.LocusId);
method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence);
- method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived();
+ method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(boolean);
method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person);
method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]);
method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int);
@@ -23294,6 +23294,7 @@
field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+ field public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = "android.media.action.SPEAKERPHONE_STATE_CHANGED";
field public static final int ADJUST_LOWER = -1; // 0xffffffff
field public static final int ADJUST_MUTE = -100; // 0xffffff9c
field public static final int ADJUST_RAISE = 1; // 0x1
@@ -28757,10 +28758,9 @@
}
public final class DnsResolver {
- method public static android.net.DnsResolver getInstance();
- method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
- method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException;
+ method @NonNull public static android.net.DnsResolver getInstance();
+ method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+ method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
field public static final int CLASS_IN = 1; // 0x1
field public static final int FLAG_EMPTY = 0; // 0x0
field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -28770,12 +28770,23 @@
field public static final int TYPE_AAAA = 28; // 0x1c
}
- public static interface DnsResolver.InetAddressAnswerListener {
- method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>);
+ public abstract static class DnsResolver.AnswerCallback<T> {
+ ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
+ method public abstract void onAnswer(@NonNull T);
+ method public abstract void onParseException(@NonNull android.net.ParseException);
+ method public abstract void onQueryException(@NonNull android.system.ErrnoException);
}
- public static interface DnsResolver.RawAnswerListener {
- method public void onAnswer(@Nullable byte[]);
+ public static interface DnsResolver.AnswerParser<T> {
+ method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
+ }
+
+ public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
+ ctor public DnsResolver.InetAddressAnswerCallback();
+ }
+
+ public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
+ ctor public DnsResolver.RawAnswerCallback();
}
public class InetAddresses {
@@ -29090,6 +29101,8 @@
}
public class ParseException extends java.lang.RuntimeException {
+ ctor public ParseException(@NonNull String);
+ ctor public ParseException(@NonNull String, @NonNull Throwable);
field public String response;
}
diff --git a/api/removed.txt b/api/removed.txt
index 4fe0ed9..fa07094 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -314,17 +314,11 @@
package android.net {
public class ConnectivityManager {
- method @Deprecated public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
method @Deprecated public boolean requestRouteToHost(int, int);
method @Deprecated public int startUsingNetworkFeature(int, String);
method @Deprecated public int stopUsingNetworkFeature(int, String);
}
- @Deprecated public abstract static class ConnectivityManager.TetheringEntitlementValueListener {
- ctor public ConnectivityManager.TetheringEntitlementValueListener();
- method public void onEntitlementResult(int);
- }
-
@Deprecated public class NetworkBadging {
method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
field public static final int BADGING_4K = 30; // 0x1e
diff --git a/api/system-current.txt b/api/system-current.txt
index 2724133..aa04d786 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4484,16 +4484,16 @@
package android.net.util {
- public class SocketUtils {
+ public final class SocketUtils {
method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method public static java.net.SocketAddress makePacketSocketAddress(short, int);
- method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+ method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
@@ -4934,6 +4934,10 @@
public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
method public int describeContents();
+ method public int getCellularDataNetworkType();
+ method public int getCellularSignalStrengthDb();
+ method public int getCellularSignalStrengthDbm();
+ method public boolean getIsSameRegisteredCell();
method public int getLinkSpeedMbps();
method public int getProbeElapsedTimeSinceLastUpdateMillis();
method public int getProbeMcsRateSinceLastUpdate();
@@ -5860,6 +5864,7 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
+ field public static final String NAMESPACE_APP_COMPAT = "app_compat";
field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
@@ -5870,6 +5875,8 @@
field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_ROLLBACK = "rollback";
+ field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_RUNTIME = "runtime";
field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
@@ -5901,13 +5908,6 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
- public static interface DeviceConfig.Rollback {
- field public static final String BOOT_NAMESPACE = "rollback_boot";
- field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
- field public static final String NAMESPACE = "rollback";
- field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
public static interface DeviceConfig.Scheduler {
field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
field public static final String NAMESPACE = "scheduler";
@@ -7236,7 +7236,6 @@
field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
- field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f
field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -7351,9 +7350,7 @@
field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
- field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804
field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
- field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805
field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
@@ -7372,6 +7369,10 @@
field public static final int MAC_FAILURE = 2183; // 0x887
field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+ field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+ field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+ field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+ field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
@@ -7480,7 +7481,6 @@
field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
- field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
field public static final int PPP_TIMEOUT = 2228; // 0x8b4
diff --git a/api/test-current.txt b/api/test-current.txt
index 4ccfa1c..7494415 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -727,6 +727,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
+ field public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis";
field public static final int STATUS_FAILURE = 1; // 0x1
field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3
field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2
@@ -1507,16 +1508,16 @@
package android.net.util {
- public class SocketUtils {
+ public final class SocketUtils {
method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method public static java.net.SocketAddress makePacketSocketAddress(short, int);
- method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+ method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
@@ -2067,6 +2068,8 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+ field public static final String NAMESPACE_ROLLBACK = "rollback";
+ field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
}
public static interface DeviceConfig.OnPropertiesChangedListener {
@@ -2092,13 +2095,6 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
- public static interface DeviceConfig.Rollback {
- field public static final String BOOT_NAMESPACE = "rollback_boot";
- field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
- field public static final String NAMESPACE = "rollback";
- field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
public final class MediaStore {
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
@@ -2548,7 +2544,8 @@
method public int getCarrierIdListVersion();
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
- method public void setCarrierTestOverride(String, String, String, String, String, String, String);
+ method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
+ method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7a753aec..1dbbbc5 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -310,7 +310,7 @@
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
TimeZoneDataInfo time_zone_data_info = 10052;
- SDCardInfo sdcard_info = 10053;
+ ExternalStorageInfo external_storage_info = 10053;
GpuStatsGlobalInfo gpu_stats_global_info = 10054;
GpuStatsAppInfo gpu_stats_app_info = 10055;
SystemIonHeapSize system_ion_heap_size = 10056;
@@ -3311,25 +3311,27 @@
}
/**
- * Logs that an SD card is mounted and information about it, its type (public or private) and the
- * size in bytes.
+ * Logs that external storage is mounted and information about it, the storage type (sd card/usb/
+ * others), its type (public or private) and the size in bytes.
* Pulled from:
* StatsCompanionService
*/
-message SDCardInfo {
+message ExternalStorageInfo {
- enum Type {
+ enum VolumeType {
UNKNOWN = 0;
- TYPE_PUBLIC = 1;
- TYPE_PRIVATE = 2;
- OTHERS = 3;
+ PUBLIC = 1;
+ PRIVATE = 2;
+ OTHER = 3;
}
- // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
- optional Type type = 1;
+ // The type of external storage.
+ optional android.stats.storage.ExternalStorageType storage_type = 1;
+ // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+ optional VolumeType volume_type = 2;
// Total size of the sd card in bytes.
- optional int64 size_bytes = 2;
+ optional int64 size_bytes = 3;
}
/*
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c7ae656..2abfc24 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -242,9 +242,9 @@
// TimeZoneDataInfo.
{android::util::TIME_ZONE_DATA_INFO,
{.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
- // SDCardInfo
- {android::util::SDCARD_INFO,
- {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
+ // ExternalStorageInfo
+ {android::util::EXTERNAL_STORAGE_INFO,
+ {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}},
// GpuStatsGlobalInfo
{android::util::GPU_STATS_GLOBAL_INFO,
{.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index db8c905..41a9921 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -781,6 +781,16 @@
isBundledApp = false;
}
+ // Similar to vendor apks, we should add /product/lib for apks from product partition
+ // and not having /product/lib in the default search path
+ final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib");
+ if (mApplicationInfo.getCodePath() != null
+ && mApplicationInfo.isProduct() && treatProductApkAsUnbundled
+ // TODO(b/128557860): Change target SDK version when version code R is available.
+ && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ isBundledApp = false;
+ }
+
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 23f64b8..523b200 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1569,12 +1569,12 @@
* Builder class for {@link Action} objects.
*/
public static final class Builder {
- private final Icon mIcon;
- private final CharSequence mTitle;
- private final PendingIntent mIntent;
+ @Nullable private final Icon mIcon;
+ @Nullable private final CharSequence mTitle;
+ @Nullable private final PendingIntent mIntent;
private boolean mAllowGeneratedReplies = true;
- private final Bundle mExtras;
- private ArrayList<RemoteInput> mRemoteInputs;
+ @NonNull private final Bundle mExtras;
+ @Nullable private ArrayList<RemoteInput> mRemoteInputs;
private @SemanticAction int mSemanticAction;
private boolean mIsContextual;
@@ -1610,9 +1610,10 @@
action.getAllowGeneratedReplies(), action.getSemanticAction());
}
- private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
- RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction) {
+ private Builder(@Nullable Icon icon, @Nullable CharSequence title,
+ @Nullable PendingIntent intent, @NonNull Bundle extras,
+ @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+ @SemanticAction int semanticAction) {
mIcon = icon;
mTitle = title;
mIntent = intent;
@@ -1645,6 +1646,7 @@
*
* <p>The returned Bundle is shared with this Builder.
*/
+ @NonNull
public Bundle getExtras() {
return mExtras;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08e0880..4d280b7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,11 +101,9 @@
import android.net.EthernetManager;
import android.net.IConnectivityManager;
import android.net.IEthernetManager;
-import android.net.IIpMemoryStore;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
import android.net.ITestNetworkManager;
-import android.net.IpMemoryStore;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
@@ -340,17 +338,6 @@
}
});
- registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
- new CachedServiceFetcher<IpMemoryStore>() {
- @Override
- public IpMemoryStore createService(final ContextImpl ctx)
- throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(
- Context.IP_MEMORY_STORE_SERVICE);
- IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
- return new IpMemoryStore(ctx, service);
- }});
-
registerService(Context.IPSEC_SERVICE, IpSecManager.class,
new CachedServiceFetcher<IpSecManager>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a4e215..9436145 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -112,6 +112,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -5171,7 +5172,8 @@
* </ul>
* The call will fail if called with the package name of an unsupported VPN app.
* <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
- * of the VPN provider could break networking for all apps.
+ * of the VPN provider could break networking for all apps. This method clears any lockdown
+ * whitelist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}.
*
* @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
* remove an existing always-on VPN configuration.
@@ -5181,11 +5183,11 @@
* @throws NameNotFoundException if {@code vpnPackage} is not installed.
* @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
* set as always-on, or if always-on VPN is not available.
- * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+ * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
boolean lockdownEnabled) throws NameNotFoundException {
- setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
+ setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptySet());
}
/**
@@ -5195,6 +5197,11 @@
* System apps can always bypass VPN.
* <p> Note that the system doesn't update the whitelist when packages are installed or
* uninstalled, the admin app must call this method to keep the list up to date.
+ * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When
+ * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or
+ * empty, only system apps can bypass VPN.
+ * <p> Setting always-on VPN package to {@code null} or using
+ * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown whitelist.
*
* @param vpnPackage package name for an installed VPN app on the device, or {@code null}
* to remove an existing always-on VPN configuration
@@ -5211,13 +5218,13 @@
* available.
*/
public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
- boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
+ boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist)
throws NameNotFoundException {
throwIfParentInstance("setAlwaysOnVpnPackage");
if (mService != null) {
try {
- mService.setAlwaysOnVpnPackage(
- admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
+ mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled,
+ lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist));
} catch (ServiceSpecificException e) {
switch (e.errorCode) {
case ERROR_VPN_PACKAGE_NOT_FOUND:
@@ -5255,7 +5262,7 @@
}
/**
- * Called by device or profile owner to query the list of packages that are allowed to access
+ * Called by device or profile owner to query the set of packages that are allowed to access
* the network directly when always-on VPN is in lockdown mode but not connected. Returns
* {@code null} when always-on VPN is not active or not in lockdown mode.
*
@@ -5263,13 +5270,15 @@
*
* @throws SecurityException if {@code admin} is not a device or a profile owner.
*
- * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+ * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
- public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
+ public @Nullable Set<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
if (mService != null) {
try {
- return mService.getAlwaysOnVpnLockdownWhitelist(admin);
+ final List<String> whitelist =
+ mService.getAlwaysOnVpnLockdownWhitelist(admin);
+ return whitelist == null ? null : new HashSet<>(whitelist);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index b6f37f6..298b003 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -26,7 +26,8 @@
import android.os.Parcelable;
/**
- * TODO(b/111701043): Add java docs
+ * Class that provides contextual information about the environment in which the app prediction is
+ * used, such as package name, UI in which the app targets are shown, and number of targets.
*
* @hide
*/
@@ -57,20 +58,32 @@
mExtras = parcel.readBundle();
}
+ /**
+ * Returns the UI surface of the prediction context.
+ */
@NonNull
public String getUiSurface() {
return mUiSurface;
}
+ /**
+ * Returns the predicted target count
+ */
public @IntRange(from = 0) int getPredictedTargetCount() {
return mPredictedTargetCount;
}
+ /**
+ * Returns the package name of the prediction context.
+ */
@NonNull
public String getPackageName() {
return mPackageName;
}
+ /**
+ * Returns the extras of the prediction context.
+ */
@Nullable
public Bundle getExtras() {
return mExtras;
@@ -100,9 +113,6 @@
dest.writeBundle(mExtras);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionContext> CREATOR =
new Parcelable.Creator<AppPredictionContext>() {
public AppPredictionContext createFromParcel(Parcel parcel) {
@@ -132,7 +142,7 @@
private Bundle mExtras;
/**
- * TODO(b/123591863): Add java docs
+ * @param context The {@link Context} of the prediction client.
*
* @hide
*/
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index 45825cf..cb5b7e7 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -23,7 +23,8 @@
import com.android.internal.util.Preconditions;
/**
- * TODO (b/111701043) : Add java doc
+ * Class that provides methods to create prediction clients.
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
index 1c5d8b4..281a16f 100644
--- a/core/java/android/app/prediction/AppPredictionSessionId.java
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -22,7 +22,7 @@
import android.os.Parcelable;
/**
- * TODO (b/111701043) : Add java doc
+ * The id for an app prediction session. See {@link AppPredictor}.
*
* @hide
*/
@@ -33,6 +33,8 @@
private final String mId;
/**
+ * Creates a new id for a prediction session.
+ *
* @hide
*/
public AppPredictionSessionId(@NonNull String id) {
@@ -58,7 +60,6 @@
@Override
public int hashCode() {
- // Ensure that the id has a consistent hash
return mId.hashCode();
}
@@ -72,9 +73,6 @@
dest.writeString(mId);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionSessionId> CREATOR =
new Parcelable.Creator<AppPredictionSessionId>() {
public AppPredictionSessionId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 284327d..3e4e8dc 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -39,7 +39,7 @@
import java.util.function.Consumer;
/**
- * TODO (b/111701043) : Add java doc
+ * Class that represents an App Prediction client.
*
* <p>
* Usage: <pre> {@code
@@ -49,14 +49,20 @@
*
* void onCreate() {
* mClient = new AppPredictor(...)
+ * mClient.registerPredictionUpdates(...)
* }
*
* void onStart() {
- * mClient.requestPredictionUpdate();
+ * mClient.requestPredictionUpdate()
+ * }
+ *
+ * void onClick(...) {
+ * mClient.notifyAppTargetEvent(...)
* }
*
* void onDestroy() {
- * mClient.close();
+ * mClient.unregisterPredictionUpdates()
+ * mClient.close()
* }
*
* }</pre>
@@ -83,7 +89,8 @@
* The caller should call {@link AppPredictor#destroy()} to dispose the client once it
* no longer used.
*
- * @param predictionContext The prediction context
+ * @param context The {@link Context} of the user of this {@link AppPredictor}.
+ * @param predictionContext The prediction context.
*/
AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
@@ -102,6 +109,8 @@
/**
* Notifies the prediction service of an app target event.
+ *
+ * @param event The {@link AppTargetEvent} that represents the app target event.
*/
public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
if (mIsClosed.get()) {
@@ -118,6 +127,9 @@
/**
* Notifies the prediction service when the targets in a launch location are shown to the user.
+ *
+ * @param launchLocation The launch location where the targets are shown to the user.
+ * @param targetIds List of {@link AppTargetId}s that are shown to the user.
*/
public void notifyLocationShown(@NonNull String launchLocation,
@NonNull List<AppTargetId> targetIds) {
@@ -138,7 +150,10 @@
* Requests the prediction service provide continuous updates of App predictions via the
* provided callback, until the given callback is unregistered.
*
- * @see Callback#onTargetsAvailable(List)
+ * @see Callback#onTargetsAvailable(List).
+ *
+ * @param callbackExecutor The callback executor to use when calling the callback.
+ * @param callback The Callback to be called when updates of App predictions are available.
*/
public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull AppPredictor.Callback callback) {
@@ -164,6 +179,10 @@
/**
* Requests the prediction service to stop providing continuous updates to the provided
* callback until the callback is re-registered.
+ *
+ * @see {@link AppPredictor#registerPredictionUpdates(Executor, Callback)}.
+ *
+ * @param callback The callback to be unregistered.
*/
public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
if (mIsClosed.get()) {
@@ -187,7 +206,7 @@
* Requests the prediction service to dispatch a new set of App predictions via the provided
* callback.
*
- * @see Callback#onTargetsAvailable(List)
+ * @see Callback#onTargetsAvailable(List).
*/
public void requestPredictionUpdate() {
if (mIsClosed.get()) {
@@ -205,6 +224,10 @@
/**
* Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
* ranker is not available.
+ *
+ * @param targets List of app targets to be sorted.
+ * @param callbackExecutor The callback executor to use when calling the callback.
+ * @param callback The callback to return the sorted list of app targets.
*/
@Nullable
public void sortTargets(@NonNull List<AppTarget> targets,
@@ -255,7 +278,7 @@
}
/**
- * TODO(b/123591863): Add java docs
+ * Returns the id of this prediction session.
*
* @hide
*/
@@ -271,7 +294,7 @@
/**
* Called when a new set of predicted app targets are available.
- * @param targets Sorted list of predicted targets
+ * @param targets Sorted list of predicted targets.
*/
void onTargetsAvailable(@NonNull List<AppTarget> targets);
}
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f09d34..bb1b96c 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -29,6 +29,7 @@
/**
* A representation of a launchable target.
+ *
* @hide
*/
@SystemApi
@@ -45,7 +46,12 @@
private int mRank;
/**
- * TODO(b/123591863): Add java docs
+ * Creates an instance of AppTarget that represent a launchable component.
+ *
+ * @param id A unique id for this launchable target.
+ * @param packageName Package name of the target.
+ * @param className Class name of the target.
+ * @param user The UserHandle of the user which this target belongs to.
*
* @hide
*/
@@ -62,7 +68,11 @@
}
/**
- * TODO(b/123591863): Add java docs
+ * Creates an instance of AppTarget that represent a launchable shortcut.
+ *
+ * @param id A unique id for this launchable target.
+ * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target.
+ * @param className Class name fo the target.
*
* @hide
*/
@@ -186,9 +196,6 @@
dest.writeInt(mRank);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR =
new Parcelable.Creator<AppTarget>() {
public AppTarget createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index f6964f3..54b9563 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -28,6 +28,7 @@
/**
* A representation of an app target event.
+ *
* @hide
*/
@SystemApi
@@ -118,9 +119,6 @@
dest.writeInt(mAction);
}
- /**
- * @see Creator
- */
public static final @android.annotation.NonNull Creator<AppTargetEvent> CREATOR =
new Creator<AppTargetEvent>() {
public AppTargetEvent createFromParcel(Parcel parcel) {
@@ -134,6 +132,7 @@
/**
* A builder for app target events.
+ *
* @hide
*/
@SystemApi
@@ -143,6 +142,10 @@
private String mLocation;
private @ActionType int mAction;
+ /**
+ * @param target The app target that is associated with this event.
+ * @param actionType The event type, which is one of the values in {@link ActionType}.
+ */
public Builder(@Nullable AppTarget target, @ActionType int actionType) {
mTarget = target;
mAction = actionType;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
index aa2ec1f..3603f5f 100644
--- a/core/java/android/app/prediction/AppTargetId.java
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -22,7 +22,8 @@
import android.os.Parcelable;
/**
- * The id for a prediction target.
+ * The id for a prediction target. See {@link AppTarget}.
+ *
* @hide
*/
@SystemApi
@@ -33,7 +34,7 @@
private final String mId;
/**
- * TODO(b/123591863): Add java docs
+ * Creates a new id for a prediction target.
*
* @hide
*/
@@ -49,6 +50,7 @@
/**
* Returns the id.
+ *
* @hide
*/
@NonNull
@@ -66,7 +68,6 @@
@Override
public int hashCode() {
- // Ensure that the id has a consistent hash
return mId.hashCode();
}
@@ -80,9 +81,6 @@
dest.writeString(mId);
}
- /**
- * @see Creator
- */
public static final @android.annotation.NonNull Creator<AppTargetId> CREATOR =
new Creator<AppTargetId>() {
public AppTargetId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 49a29f0a..fb933b1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3703,14 +3703,6 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.net.IpMemoryStore} to store and read information about
- * known networks.
- * @hide
- */
- public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
-
- /**
- * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
*
@@ -4016,6 +4008,16 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link com.android.server.attention.AttentionManagerService} for attention services.
+ *
+ * @see #getSystemService(String)
+ * @see android.server.attention.AttentionManagerService
+ * @hide
+ */
+ public static final String ATTENTION_SERVICE = "attention";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.view.inputmethod.InputMethodManager} for accessing input
* methods.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a2d3f6a..efd9990 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1997,7 +1997,8 @@
public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
/**
- * Intent extra: ID of the shortcut used to send the share intent.
+ * Intent extra: ID of the shortcut used to send the share intent. Will be sent with
+ * {@link #ACTION_SEND}.
*
* @see ShortcutInfo#getId()
*
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7b61807..1f82fa6 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1270,8 +1270,8 @@
* system services even after it has been unpublished as a dynamic shortcut.
*/
@NonNull
- public Builder setLongLived() {
- mIsLongLived = true;
+ public Builder setLongLived(boolean londLived) {
+ mIsLongLived = londLived;
return this;
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9038b03..293c1e4 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -24,6 +24,7 @@
import android.annotation.TestApi;
import android.content.Context;
import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
import android.content.pm.ParceledListSlice;
import android.content.pm.VersionedPackage;
import android.os.RemoteException;
@@ -48,6 +49,24 @@
private final String mCallerPackageName;
private final IRollbackManager mBinder;
+ /**
+ * Lifetime duration of rollback packages in millis. A rollback will be available for
+ * at most that duration of time after a package is installed with
+ * {@link PackageInstaller.SessionParams#setEnableRollback()}.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * @see RollbackManager
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK_BOOT
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS =
+ "rollback_lifetime_in_millis";
+
/** {@hide} */
public RollbackManager(Context context, IRollbackManager binder) {
mCallerPackageName = context.getPackageName();
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 6ea35f0..bae0fd3 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -315,7 +315,7 @@
/**
* The sensor is dirty. The user should be informed to clean the sensor.
*/
- public static final int SENSOR_DIRTY = 21;
+ public static final int FACE_ACQUIRED_SENSOR_DIRTY = 21;
/**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 7fa1cfb..21fcc63 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -80,15 +80,23 @@
* Histogram counting how many times a pixel of a given value was displayed onscreen for the
* Value component of HSV if the device supports color sampling, if the device does not support
* color sampling the value will be null.
+ *
* The buckets of the histogram are evenly weighted, the number of buckets is device specific.
- * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range
- * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc.
+ * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+ * for 1 millisecond.
+ * For example if we had {100, 50, 30, 20}, value component was onscreen for 100 pixel
+ * milliseconds in range 0x00->0x3F, 30 pixel milliseconds in range 0x40->0x7F, etc.
+ *
+ * {@see #colorSampleDuration}
*/
@Nullable
public final long[] colorValueBuckets;
/**
- * How many milliseconds of data are contained in the colorValueBuckets.
+ * How many milliseconds of data are contained in the colorValueBuckets, if the device does
+ * not support color sampling the value will be 0L.
+ *
+ * {@see #colorValueBuckets}
*/
public final long colorSampleDuration;
@@ -283,7 +291,8 @@
return this;
}
- /** {@see BrightnessChangeEvent#valueBuckets} */
+ /** {@see BrightnessChangeEvent#colorValueBuckets}
+ * {@see BrightnessChangeEvent#colorSampleDuration} */
public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) {
Objects.requireNonNull(colorValueBuckets);
mColorValueBuckets = colorValueBuckets;
diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java
index 0610377..4a429bb 100644
--- a/core/java/android/hardware/display/DisplayedContentSample.java
+++ b/core/java/android/hardware/display/DisplayedContentSample.java
@@ -30,12 +30,14 @@
* Construct an object representing a color histogram of pixels that were displayed on screen.
*
* @param numFrames The number of frames represented by this sample.
- * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value
- * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly
- * weighted, the number of buckets is device specific.
- * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were
- * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range
- * 0x40->0x7F, etc.
+ * @param mSamplesComponent0 is a histogram counting how many times and for how long a pixel
+ * of a given value was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the
+ * histogram are evenly weighted, the number of buckets is device specific.
+ * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+ * onscreen for 1ms.
+ * eg, for RGBA_8888, if sampleComponent0 is {100, 50, 30, 20}, then red component was
+ * onscreen for 100 pixel milliseconds in range 0x00->0x3F, 30 pixel milliseconds in
+ * range 0x40->0x7F, etc.
* @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the
* second component of format.
* @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 139a5ee..3e8c334 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -634,6 +634,8 @@
return context.getString(R.string.face_acquired_obscured);
case FACE_ACQUIRED_START:
return null;
+ case FACE_ACQUIRED_SENSOR_DIRTY:
+ return context.getString(R.string.face_acquired_sensor_dirty);
case FACE_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
R.array.face_acquired_vendor);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d08379f..e5802c2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2816,23 +2816,6 @@
}
/**
- * @removed
- * @deprecated This API would be removed when all of caller has been updated.
- * */
- @Deprecated
- public abstract static class TetheringEntitlementValueListener {
- /**
- * Called to notify entitlement result.
- *
- * @param resultCode a int value of entitlement result. It may be one of
- * {@link #TETHER_ERROR_NO_ERROR},
- * {@link #TETHER_ERROR_PROVISION_FAILED}, or
- * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
- */
- public void onEntitlementResult(int resultCode) {}
- }
-
- /**
* Get the last value of the entitlement check on this downstream. If the cached value is
* {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
* cached value. Otherwise, a UI-based entitlement check would be performed. It is not
@@ -2878,31 +2861,6 @@
}
/**
- * @removed
- * @deprecated This API would be removed when all of caller has been updated.
- * */
- @Deprecated
- public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi,
- @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) {
- Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null.");
- ResultReceiver wrappedListener = new ResultReceiver(handler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- listener.onEntitlementResult(resultCode);
- }
- };
-
- try {
- String pkgName = mContext.getOpPackageName();
- Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName);
- mService.getLatestTetheringEntitlementResult(type, wrappedListener,
- showEntitlementUi, pkgName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Report network connectivity status. This is currently used only
* to alter status bar UI.
* <p>This method requires the caller to hold the permission
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
index 0ac02b1..83e57e0 100644
--- a/core/java/android/net/DnsPacket.java
+++ b/core/java/android/net/DnsPacket.java
@@ -71,7 +71,7 @@
}
/**
- * It's used both for DNS questions and DNS resource records.
+ * Superclass for DNS questions and DNS resource records.
*
* DNS questions (No TTL/RDATA)
* DNS resource records (With TTL/RDATA)
@@ -96,12 +96,13 @@
/**
* Create a new DnsRecord from a positioned ByteBuffer.
*
- * @param ByteBuffer input of record, must be in network byte order
- * (which is the default).
* Reads the passed ByteBuffer from its current position and decodes a DNS record.
* When this constructor returns, the reading position of the ByteBuffer has been
* advanced to the end of the DNS header record.
* This is meant to chain with other methods reading a DNS response in sequence.
+ *
+ * @param ByteBuffer input of record, must be in network byte order
+ * (which is the default).
*/
DnsRecord(int recordType, @NonNull ByteBuffer buf)
throws BufferUnderflowException, ParseException {
@@ -205,16 +206,6 @@
protected final DnsHeader mHeader;
protected final List<DnsRecord>[] mRecords;
- public static class ParseException extends Exception {
- public ParseException(String msg) {
- super(msg);
- }
-
- public ParseException(String msg, Throwable cause) {
- super(msg, cause);
- }
- }
-
protected DnsPacket(@NonNull byte[] data) throws ParseException {
if (null == data) throw new ParseException("Parse header failed, null input data");
final ByteBuffer buffer;
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index d3bc3e6..93b8cf8 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,11 +22,11 @@
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.MessageQueue;
+import android.os.Looper;
import android.system.ErrnoException;
import android.util.Log;
@@ -37,8 +37,7 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Consumer;
-
+import java.util.concurrent.Executor;
/**
* Dns resolver class for asynchronous dns querying
@@ -81,66 +80,137 @@
public static final int FLAG_NO_CACHE_STORE = 1 << 1;
public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
- private static final int DNS_RAW_RESPONSE = 1;
-
private static final int NETID_UNSET = 0;
private static final DnsResolver sInstance = new DnsResolver();
/**
- * listener for receiving raw answers
- */
- public interface RawAnswerListener {
- /**
- * {@code byte[]} is {@code null} if query timed out
- */
- void onAnswer(@Nullable byte[] answer);
- }
-
- /**
- * listener for receiving parsed answers
- */
- public interface InetAddressAnswerListener {
- /**
- * Will be called exactly once with all the answers to the query.
- * size of addresses will be zero if no available answer could be parsed.
- */
- void onAnswer(@NonNull List<InetAddress> addresses);
- }
-
- /**
* Get instance for DnsResolver
*/
- public static DnsResolver getInstance() {
+ public static @NonNull DnsResolver getInstance() {
return sInstance;
}
private DnsResolver() {}
/**
- * Pass in a blob and corresponding setting,
- * get a blob back asynchronously with the entire raw answer.
+ * Answer parser for parsing raw answers
+ *
+ * @param <T> The type of the parsed answer
+ */
+ public interface AnswerParser<T> {
+ /**
+ * Creates a <T> answer by parsing the given raw answer.
+ *
+ * @param rawAnswer the raw answer to be parsed
+ * @return a parsed <T> answer
+ * @throws ParseException if parsing failed
+ */
+ @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
+ }
+
+ /**
+ * Base class for answer callbacks
+ *
+ * @param <T> The type of the parsed answer
+ */
+ public abstract static class AnswerCallback<T> {
+ /** @hide */
+ public final AnswerParser<T> parser;
+
+ public AnswerCallback(@NonNull AnswerParser<T> parser) {
+ this.parser = parser;
+ };
+
+ /**
+ * Success response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked when the answer to a query was successfully parsed.
+ *
+ * @param answer parsed answer to the query.
+ *
+ * {@see android.net.DnsResolver#query query()}
+ */
+ public abstract void onAnswer(@NonNull T answer);
+
+ /**
+ * Error response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked when there is no valid answer to
+ * {@link android.net.DnsResolver#query query()}
+ *
+ * @param exception a {@link ParseException} object with additional
+ * detail regarding the failure
+ */
+ public abstract void onParseException(@NonNull ParseException exception);
+
+ /**
+ * Error response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked if an error happens when
+ * issuing the DNS query or receiving the result.
+ * {@link android.net.DnsResolver#query query()}
+ *
+ * @param exception an {@link ErrnoException} object with additional detail
+ * regarding the failure
+ */
+ public abstract void onQueryException(@NonNull ErrnoException exception);
+ }
+
+ /**
+ * Callback for receiving raw answers
+ */
+ public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
+ public RawAnswerCallback() {
+ super(rawAnswer -> rawAnswer);
+ }
+ }
+
+ /**
+ * Callback for receiving parsed {@link InetAddress} answers
+ *
+ * Note that if the answer does not contain any IP addresses,
+ * onAnswer will be called with an empty list.
+ */
+ public abstract static class InetAddressAnswerCallback
+ extends AnswerCallback<List<InetAddress>> {
+ public InetAddressAnswerCallback() {
+ super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+ }
+ }
+
+ /**
+ * Send a raw DNS query.
+ * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
* @param network {@link Network} specifying which network for querying.
* {@code null} for query on default network.
* @param query blob message
* @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link RawAnswerListener} will be invoked.
- * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param callback an {@link AnswerCallback} which will be called to notify the caller
* of the result of dns query.
*/
- public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
- final FileDescriptor queryfd = resNetworkSend((network != null
+ public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkSend((network != null
? network.netId : NETID_UNSET), query, query.length, flags);
- registerFDListener(handler.getLooper().getQueue(), queryfd,
- answerbuf -> listener.onAnswer(answerbuf));
+ } catch (ErrnoException e) {
+ callback.onQueryException(e);
+ return;
+ }
+
+ registerFDListener(executor, queryfd, callback);
}
/**
- * Pass in a domain name and corresponding setting,
- * get a blob back asynchronously with the entire raw answer.
+ * Send a DNS query with the specified name, class and query type.
+ * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
* @param network {@link Network} specifying which network for querying.
* {@code null} for query on default network.
@@ -148,74 +218,53 @@
* @param nsClass dns class as one of the CLASS_* constants
* @param nsType dns resource record (RR) type as one of the TYPE_* constants
* @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link RawAnswerListener} will be invoked.
- * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param callback an {@link AnswerCallback} which will be called to notify the caller
* of the result of dns query.
*/
- public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass,
- @QueryType int nsType, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
- final FileDescriptor queryfd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
- registerFDListener(handler.getLooper().getQueue(), queryfd,
- answerbuf -> listener.onAnswer(answerbuf));
+ public <T> void query(@Nullable Network network, @NonNull String domain,
+ @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkQuery((network != null
+ ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+ } catch (ErrnoException e) {
+ callback.onQueryException(e);
+ return;
+ }
+ registerFDListener(executor, queryfd, callback);
}
- /**
- * Pass in a domain name and corresponding setting,
- * get back a set of InetAddresses asynchronously.
- *
- * @param network {@link Network} specifying which network for querying.
- * {@code null} for query on default network.
- * @param domain domain name for querying
- * @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link InetAddressAnswerListener} will be invoked.
- * @param listener an {@link InetAddressAnswerListener} which will be called to
- * notify the caller of the result of dns query.
- *
- */
- public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull InetAddressAnswerListener listener)
- throws ErrnoException {
- final FileDescriptor v4fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
- final FileDescriptor v6fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
-
- final InetAddressAnswerAccumulator accmulator =
- new InetAddressAnswerAccumulator(2, listener);
- final Consumer<byte[]> consumer = answerbuf ->
- accmulator.accumulate(parseAnswers(answerbuf));
-
- registerFDListener(handler.getLooper().getQueue(), v4fd, consumer);
- registerFDListener(handler.getLooper().getQueue(), v6fd, consumer);
- }
-
- private void registerFDListener(@NonNull MessageQueue queue,
- @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) {
- queue.addOnFileDescriptorEventListener(
+ private <T> void registerFDListener(@NonNull Executor executor,
+ @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+ Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
- byte[] answerbuf = null;
- try {
- // TODO: Implement result function in Java side instead of using JNI
- // Because JNI method close fd prior than unregistering fd on
- // event listener.
- answerbuf = resNetworkResult(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "resNetworkResult:" + e.toString());
- }
- answerConsumer.accept(answerbuf);
+ executor.execute(() -> {
+ byte[] answerbuf = null;
+ try {
+ answerbuf = resNetworkResult(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "resNetworkResult:" + e.toString());
+ answerCallback.onQueryException(e);
+ return;
+ }
+ try {
+ answerCallback.onAnswer(
+ answerCallback.parser.parse(answerbuf));
+ } catch (ParseException e) {
+ answerCallback.onParseException(e);
+ }
+ });
// Unregister this fd listener
return 0;
});
}
- private class DnsAddressAnswer extends DnsPacket {
+ private static class DnsAddressAnswer extends DnsPacket {
private static final String TAG = "DnsResolver.DnsAddressAnswer";
private static final boolean DBG = false;
@@ -226,12 +275,6 @@
if ((mHeader.flags & (1 << 15)) == 0) {
throw new ParseException("Not an answer packet");
}
- if (mHeader.rcode != 0) {
- throw new ParseException("Response error, rcode:" + mHeader.rcode);
- }
- if (mHeader.getRecordCount(ANSECTION) == 0) {
- throw new ParseException("No available answer");
- }
if (mHeader.getRecordCount(QDSECTION) == 0) {
throw new ParseException("No question found");
}
@@ -241,6 +284,8 @@
public @NonNull List<InetAddress> getAddresses() {
final List<InetAddress> results = new ArrayList<InetAddress>();
+ if (mHeader.getRecordCount(ANSECTION) == 0) return results;
+
for (final DnsRecord ansSec : mRecords[ANSECTION]) {
// Only support A and AAAA, also ignore answers if query type != answer type.
int nsType = ansSec.nsType;
@@ -259,34 +304,4 @@
}
}
- private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) {
- try {
- return (data == null) ? null : new DnsAddressAnswer(data).getAddresses();
- } catch (DnsPacket.ParseException e) {
- Log.e(TAG, "Parse answer fail " + e.getMessage());
- return null;
- }
- }
-
- private class InetAddressAnswerAccumulator {
- private final List<InetAddress> mAllAnswers;
- private final InetAddressAnswerListener mAnswerListener;
- private final int mTargetAnswerCount;
- private int mReceivedAnswerCount = 0;
-
- InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) {
- mTargetAnswerCount = size;
- mAllAnswers = new ArrayList<>();
- mAnswerListener = listener;
- }
-
- public void accumulate(@Nullable List<InetAddress> answer) {
- if (null != answer) {
- mAllAnswers.addAll(answer);
- }
- if (++mReceivedAnswerCount == mTargetAnswerCount) {
- mAnswerListener.onAnswer(mAllAnswers);
- }
- }
- }
}
diff --git a/media/java/android/media/session/SessionLink.aidl b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
similarity index 69%
rename from media/java/android/media/session/SessionLink.aidl
rename to core/java/android/net/IIpMemoryStoreCallbacks.aidl
index c3be23e..53108db 100644
--- a/media/java/android/media/session/SessionLink.aidl
+++ b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,6 +14,11 @@
* limitations under the License.
*/
-package android.media.session;
+package android.net;
-parcelable SessionLink;
+import android.net.IIpMemoryStore;
+
+/** {@hide} */
+oneway interface IIpMemoryStoreCallbacks {
+ void onIpMemoryStoreFetched(in IIpMemoryStore ipMemoryStore);
+}
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index edb9df6..3751c36 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,6 +15,7 @@
*/
package android.net;
+import android.net.IIpMemoryStoreCallbacks;
import android.net.INetworkMonitorCallbacks;
import android.net.Network;
import android.net.dhcp.DhcpServingParamsParcel;
@@ -27,4 +28,5 @@
in IDhcpServerCallbacks cb);
void makeNetworkMonitor(in Network network, String name, in INetworkMonitorCallbacks cb);
void makeIpClient(in String ifName, in IIpClientCallbacks callbacks);
-}
\ No newline at end of file
+ void fetchIpMemoryStore(in IIpMemoryStoreCallbacks cb);
+}
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c638491..c97b37b 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -19,11 +19,9 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
import com.google.android.collect.Sets;
-import java.net.InetAddress;
import java.util.HashSet;
/**
@@ -117,40 +115,6 @@
}
/**
- * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
- */
- public static InterfaceConfiguration fromParcel(InterfaceConfigurationParcel p) {
- InterfaceConfiguration cfg = new InterfaceConfiguration();
- cfg.setHardwareAddress(p.hwAddr);
-
- final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
- cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
- for (String flag : p.flags) {
- cfg.setFlag(flag);
- }
-
- return cfg;
- }
-
- /**
- * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
- */
- public InterfaceConfigurationParcel toParcel(String iface) {
- InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
- cfgParcel.ifName = iface;
- if (!TextUtils.isEmpty(mHwAddr)) {
- cfgParcel.hwAddr = mHwAddr;
- } else {
- cfgParcel.hwAddr = "";
- }
- cfgParcel.ipv4Addr = mAddr.getAddress().getHostAddress();
- cfgParcel.prefixLength = mAddr.getPrefixLength();
- cfgParcel.flags = mFlags.toArray(EMPTY_STRING_ARRAY);
-
- return cfgParcel;
- }
-
- /**
* This function determines if the interface is up and has a valid IP
* configuration (IP address has a non zero octet).
*
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d42fce3..ae421a4 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -40,6 +40,7 @@
import android.util.BackupUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.io.ByteArrayOutputStream;
@@ -89,10 +90,22 @@
private static boolean sForceAllNetworkTypes = false;
+ /**
+ * Results in matching against all mobile network types.
+ *
+ * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
+ */
+ @VisibleForTesting
public static void forceAllNetworkTypes() {
sForceAllNetworkTypes = true;
}
+ /** Resets the affect of {@link #forceAllNetworkTypes}. */
+ @VisibleForTesting
+ public static void resetForceAllNetworkTypes() {
+ sForceAllNetworkTypes = false;
+ }
+
/**
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
* the given IMSI.
diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java
index 2380e86..9d4727a 100644
--- a/core/java/android/net/ParseException.java
+++ b/core/java/android/net/ParseException.java
@@ -16,15 +16,22 @@
package android.net;
+import android.annotation.NonNull;
+
/**
- * Thrown when parsing a URL fails.
+ * Thrown when parsing failed.
*/
// See non-public class {@link WebAddress}.
public class ParseException extends RuntimeException {
public String response;
- ParseException(String response) {
+ public ParseException(@NonNull String response) {
super(response);
this.response = response;
}
+
+ public ParseException(@NonNull String response, @NonNull Throwable cause) {
+ super(response, cause);
+ this.response = response;
+ }
}
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index d4a4cf4..e56f059 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -19,14 +19,17 @@
import static android.os.UserHandle.PER_USER_RANGE;
import android.os.Parcel;
+import android.os.Parcelable;
/**
* An inclusive range of UIDs.
*
* @hide
*/
-public final class UidRange extends UidRangeParcel {
- private UidRange() {}
+public final class UidRange implements Parcelable {
+ public final int start;
+ public final int stop;
+
public UidRange(int startUid, int stopUid) {
if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
@@ -86,18 +89,28 @@
return start + "-" + stop;
}
- /**
- * DO NOT override "writeToParcel" and "readFromParcel" in this class.
- * The parceling code is autogenerated by the superclass.
- */
+ // Implement the Parcelable interface
+ // TODO: Consider making this class no longer parcelable, since all users are likely in the
+ // system server.
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(start);
+ dest.writeInt(stop);
+ }
public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
new Creator<UidRange>() {
@Override
public UidRange createFromParcel(Parcel in) {
- UidRange obj = new UidRange();
- obj.readFromParcel(in);
- return obj;
+ int start = in.readInt();
+ int stop = in.readInt();
+
+ return new UidRange(start, stop);
}
@Override
public UidRange[] newArray(int size) {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 870d8b1..ea245a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -27,6 +27,8 @@
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
@@ -48,6 +50,7 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* VpnService is a base class for applications to extend and build their
@@ -138,7 +141,7 @@
* provides users with the ability to set it as always-on, so that VPN connection is
* persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
* owner and profile owner apps through
- * {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage}.
+ * {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
*
* <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
* {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
@@ -370,7 +373,10 @@
}
/**
- * Returns whether the service is running in always-on VPN mode.
+ * Returns whether the service is running in always-on VPN mode. In this mode the system ensures
+ * that the service is always running by restarting it when necessary, e.g. after reboot.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public final boolean isAlwaysOn() {
try {
@@ -381,8 +387,11 @@
}
/**
- * Returns whether the service is running in always-on VPN mode blocking connections without
- * VPN.
+ * Returns whether the service is running in always-on VPN lockdown mode. In this mode the
+ * system ensures that the service is always running and that the apps aren't allowed to bypass
+ * the VPN.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public final boolean isLockdownEnabled() {
try {
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 5827f9e..6f8aece 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -45,7 +45,7 @@
*/
@SystemApi
@TestApi
-public class SocketUtils {
+public final class SocketUtils {
/**
* Create a raw datagram socket that is bound to an interface.
*
@@ -63,6 +63,7 @@
/**
* Make a socket address to communicate with netlink.
*/
+ @NonNull
public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
return new NetlinkSocketAddress(portId, groupsMask);
}
@@ -70,13 +71,15 @@
/**
* Make socket address that packet sockets can bind to.
*/
- public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
- return new PacketSocketAddress(protocol, ifIndex);
+ @NonNull
+ public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
+ return new PacketSocketAddress((short) protocol, ifIndex);
}
/**
* Make a socket address that packet socket can send packets to.
*/
+ @NonNull
public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
return new PacketSocketAddress(ifIndex, hwAddr);
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 39e9138..707a404 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -82,12 +82,18 @@
public void setup(Context context, Bundle coreSettings) {
final PackageManager pm = context.getPackageManager();
final String packageName = context.getPackageName();
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
setupAngle(context, coreSettings, pm, packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
if (!chooseDriver(context, coreSettings, pm, packageName)) {
setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
}
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
/**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6d32f8c..cc73786 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -78,6 +78,15 @@
"activity_manager_native_boot";
/**
+ * Namespace for all app compat related features. These features will be applied
+ * immediately upon change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_APP_COMPAT = "app_compat";
+
+ /**
* Namespace for AttentionManagerService related features.
*
* @hide
@@ -163,6 +172,22 @@
public static final String NAMESPACE_NETD_NATIVE = "netd_native";
/**
+ * Namespace for Rollback flags that are applied immediately.
+ *
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final String NAMESPACE_ROLLBACK = "rollback";
+
+ /**
+ * Namespace for Rollback flags that are applied after a reboot.
+ *
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
+
+ /**
* Namespace for all runtime related features that don't require a reboot to become active.
* There are no feature flags using NAMESPACE_RUNTIME.
*
@@ -261,50 +286,6 @@
}
/**
- * Namespace for Rollback.
- *
- * @hide
- */
- @SystemApi @TestApi
- public interface Rollback {
-
- /**
- * Namespace for flags that can be changed immediately after becoming available on device.
- */
- String NAMESPACE = "rollback";
-
- /**
- * Namespace for flags that can be changed only after reboot.
- */
- String BOOT_NAMESPACE = "rollback_boot";
-
- /**
- * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
- * rollback within that period, the install will proceed without rollback enabled.
- *
- * <p>If flag value is negative, the default value will be assigned.
- *
- * Flag type: {@code long}
- * Namespace: Rollback.NAMESPACE
- */
- String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-
- /**
- * Lifetime duration of rollback packages in millis. A rollback will be available for
- * at most that duration of time after a package is installed with
- * {@link PackageInstaller.SessionParams#setEnableRollback()}.
- *
- * <p>If flag value is negative, the default value will be assigned.
- *
- * @see RollbackManager
- *
- * Flag type: {@code long}
- * Namespace: Rollback.BOOT_NAMESPACE
- */
- String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
- /**
* Namespace for storage-related features.
*
* @hide
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 6d88530..4413585 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,9 @@
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
- initialApplication.getAssets().addAssetPathAsSharedLibrary(
- webViewContext.getApplicationInfo().sourceDir);
+ for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) {
+ initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
+ }
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f250666..faf0c7d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -680,7 +680,7 @@
& DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
}
}
- } catch (SecurityException e) {
+ } catch (SecurityException | NullPointerException e) {
Log.w(TAG, "Error loading file preview", e);
}
@@ -918,6 +918,8 @@
if (isSendAction(in)) {
in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+
+ in.fixUris(getUserId());
}
}
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 8fce94e..9bf1825 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -318,6 +318,16 @@
// Whether battery saver is enabled.
optional bool enabled = 1;
+ enum StateEnum {
+ STATE_UNKNOWN = 0;
+ STATE_OFF = 1;
+ STATE_MANUAL_ON = 2;
+ STATE_AUTOMATIC_ON = 3;
+ STATE_OFF_AUTOMATIC_SNOOZED = 4;
+ STATE_PENDING_STICKY_ON = 5;
+ }
+ optional StateEnum state = 18;
+
// Whether full battery saver is enabled.
optional bool is_full_enabled = 14;
@@ -337,8 +347,7 @@
// Whether battery status has been set at least once.
optional bool battery_status_set = 4;
- // Whether automatic battery saver has been canceled by the user.
- optional bool battery_saver_snoozing = 5;
+ reserved 5; // battery_saver_snoozing
// Whether the device is connected to any power source.
optional bool is_powered = 6;
@@ -373,5 +382,5 @@
// using elapsed realtime as the timebase.
optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17;
- // Next tag: 18
+ // Next tag: 19
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbea13e..fe2c665 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,8 +118,11 @@
<attr name="manageSpaceActivity" format="string" />
<!-- Option to let applications specify that user data can/cannot be
- cleared by the user in Settings. This flag is turned on by default.
- <em>This attribute is usable only by applications
+ cleared. This flag is turned on by default.
+ <p>Starting from API level 29 this flag only controls if the user can
+ clear app data from Settings. To control clearing the data after a
+ failed restore use allowClearUserDataOnFailedRestore flag.
+ <p><em>This attribute is usable only by applications
included in the system image. Third-party apps cannot use it.</em> -->
<attr name="allowClearUserData" format="boolean" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2b13c4e..74970e8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1538,43 +1538,45 @@
<string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
<!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
- <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string>
+ <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string>
<!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
- <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string>
+ <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
<!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
- <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string>
+ <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string>
<!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_close">Please move sensor farther from face.</string>
+ <string name="face_acquired_too_close">Move phone farther away.</string>
<!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_far">Please bring sensor closer to face.</string>
+ <string name="face_acquired_too_far">Move phone closer.</string>
<!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_high">Please move sensor higher.</string>
+ <string name="face_acquired_too_high">Move phone higher.</string>
<!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_low">Please move sensor lower.</string>
+ <string name="face_acquired_too_low">Move phone lower.</string>
<!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_right">Please move sensor to the right.</string>
+ <string name="face_acquired_too_right">Move phone to the right.</string>
<!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_left">Please move sensor to the left.</string>
+ <string name="face_acquired_too_left">Move phone to the left.</string>
<!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
+ <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string>
<!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
- <string name="face_acquired_not_detected">No face detected.</string>
+ <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
<!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
- <string name="face_acquired_too_much_motion">Too much motion.</string>
+ <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
<!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
<string name="face_acquired_recalibrate">Please re-enroll your face.</string>
<!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_different">Different face detected.</string>
+ <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string>
<!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
<string name="face_acquired_too_similar">Too similar, please change your pose.</string>
<!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
- <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string>
+ <string name="face_acquired_pan_too_extreme">Please look more directly at the screen.</string>
<!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
- <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string>
+ <string name="face_acquired_tilt_too_extreme">Please look more directly at the screen.</string>
<!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
<string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
<!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
- <string name="face_acquired_obscured">Please uncover your face.</string>
+ <string name="face_acquired_obscured">Clear the space between your head and the phone.</string>
+ <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
+ <string name="face_acquired_sensor_dirty">Please clean the camera.</string>
<!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_acquired_vendor">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5fc104..17ccc31 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2546,6 +2546,7 @@
<java-symbol type="string" name="face_acquired_tilt_too_extreme" />
<java-symbol type="string" name="face_acquired_roll_too_extreme" />
<java-symbol type="string" name="face_acquired_obscured" />
+ <java-symbol type="string" name="face_acquired_sensor_dirty" />
<java-symbol type="array" name="face_acquired_vendor" />
<java-symbol type="string" name="face_name_template" />
<java-symbol type="string" name="face_authenticated_no_confirmation_required" />
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 105af6e8..51c4252 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,7 +16,6 @@
package android.security.keystore;
-import libcore.util.EmptyArray;
import android.security.Credentials;
import android.security.GateKeeper;
import android.security.KeyStore;
@@ -31,6 +30,8 @@
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
+import libcore.util.EmptyArray;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -123,7 +124,14 @@
final Certificate[] caList;
- final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
+ // Suppress the key not found warning for this call. It seems that this error is exclusively
+ // being thrown when there is a self signed certificate chain, so when the keystore service
+ // attempts to query for the CA details, it obviously fails to find them and returns a
+ // key not found exception. This is WAI, and throwing a stack trace here can be very
+ // misleading since the trace is not clear.
+ final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
+ mUid,
+ true /* suppressKeyNotFoundWarning */);
if (caBytes != null) {
final Collection<X509Certificate> caChain = toCertificates(caBytes);
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index c512a6b..9a95fdf 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -292,8 +292,10 @@
pAsset = new _FileAsset;
result = pAsset->openChunk(dataMap);
- if (result != NO_ERROR)
+ if (result != NO_ERROR) {
+ delete pAsset;
return NULL;
+ }
pAsset->mAccessMode = mode;
return pAsset;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index aeeb32c..8f7e814 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -18,6 +18,7 @@
#include "hwui/Bitmap.h"
#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
@@ -25,7 +26,9 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
+#include <GrContext.h>
#include <SkCanvas.h>
+#include <SkImage.h>
#include <utils/GLUtils.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
@@ -33,58 +36,247 @@
namespace android::uirenderer {
-static std::mutex sLock{};
-static sp<ThreadBase> sUploadThread = nullptr;
-static renderthread::EglManager sEglManager;
-static int sPendingUploads = 0;
-static nsecs_t sLastUpload = 0;
+class AHBUploader;
+// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
+// interface.
+static sp<AHBUploader> sUploader = nullptr;
-static bool shouldTimeOutLocked() {
- nsecs_t durationSince = systemTime() - sLastUpload;
- return durationSince > 2000_ms;
-}
+struct FormatInfo {
+ PixelFormat pixelFormat;
+ GLint format, type;
+ VkFormat vkFormat;
+ bool isSupported = false;
+ bool valid = true;
+};
-static void checkIdleTimeout() {
- std::lock_guard _lock{sLock};
- if (sPendingUploads == 0 && shouldTimeOutLocked()) {
- sEglManager.destroy();
- } else {
- sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
- }
-}
+class AHBUploader : public RefBase {
+public:
+ virtual ~AHBUploader() {}
-static void beginUpload() {
- std::lock_guard _lock{sLock};
- sPendingUploads++;
-
- if (!sUploadThread) {
- sUploadThread = new ThreadBase{};
+ // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
+ // need to do an upload.
+ void initialize() {
+ onInitialize();
}
- if (!sUploadThread->isRunning()) {
- sUploadThread->start("GrallocUploadThread");
+ void destroy() {
+ std::lock_guard _lock{mLock};
+ LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
+ if (mUploadThread) {
+ mUploadThread->requestExit();
+ mUploadThread->join();
+ mUploadThread = nullptr;
+ }
+ onDestroy();
}
- if (!sEglManager.hasEglContext()) {
- sUploadThread->queue().runSync([]() {
- sEglManager.initialize();
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) {
+ ATRACE_CALL();
+ beginUpload();
+ bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer);
+ endUpload();
+ return result;
+ }
+
+ void postIdleTimeoutCheck() {
+ mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
+ }
+
+protected:
+ std::mutex mLock;
+ sp<ThreadBase> mUploadThread = nullptr;
+
+private:
+ virtual void onInitialize() = 0;
+ virtual void onIdle() = 0;
+ virtual void onDestroy() = 0;
+
+ virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) = 0;
+ virtual void onBeginUpload() = 0;
+
+ bool shouldTimeOutLocked() {
+ nsecs_t durationSince = systemTime() - mLastUpload;
+ return durationSince > 2000_ms;
+ }
+
+ void idleTimeoutCheck() {
+ std::lock_guard _lock{mLock};
+ if (mPendingUploads == 0 && shouldTimeOutLocked()) {
+ onIdle();
+ } else {
+ this->postIdleTimeoutCheck();
+ }
+ }
+
+ void beginUpload() {
+ std::lock_guard _lock{mLock};
+ mPendingUploads++;
+
+ if (!mUploadThread) {
+ mUploadThread = new ThreadBase{};
+ }
+ if (!mUploadThread->isRunning()) {
+ mUploadThread->start("GrallocUploadThread");
+ }
+
+ onBeginUpload();
+ }
+
+ void endUpload() {
+ std::lock_guard _lock{mLock};
+ mPendingUploads--;
+ mLastUpload = systemTime();
+ }
+
+ int mPendingUploads = 0;
+ nsecs_t mLastUpload = 0;
+};
+
+#define FENCE_TIMEOUT 2000000000
+
+class EGLUploader : public AHBUploader {
+private:
+ void onInitialize() override {}
+ void onDestroy() override {
+ mEglManager.destroy();
+ }
+ void onIdle() override {
+ mEglManager.destroy();
+ }
+
+ void onBeginUpload() override {
+ if (!mEglManager.hasEglContext()) {
+ mUploadThread->queue().runSync([this]() {
+ this->mEglManager.initialize();
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ });
+
+ this->postIdleTimeoutCheck();
+ }
+ }
+
+
+ EGLDisplay getUploadEglDisplay() {
+ std::lock_guard _lock{mLock};
+ LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
+ return mEglManager.eglDisplay();
+ }
+
+ bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) override {
+ ATRACE_CALL();
+
+ EGLDisplay display = getUploadEglDisplay();
+
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ AutoEglImage autoImage(display, clientBuffer);
+ if (autoImage.image == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image, err =%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ return false;
+ }
+
+ {
+ ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
+ EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
+ AutoSkiaGlTexture glTexture;
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+ GL_CHECKPOINT(MODERATE);
+
+ // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
+ // provide.
+ // But asynchronous in sense that driver may upload texture onto hardware buffer
+ // when we first use it in drawing
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+ format.format, format.type, bitmap.getPixels());
+ GL_CHECKPOINT(MODERATE);
+
+ EGLSyncKHR uploadFence =
+ eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+ LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
+ "Could not create sync fence %#x", eglGetError());
+ glFlush();
+ return uploadFence;
+ });
+
+ EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
+ LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+ "Failed to wait for the fence %#x", eglGetError());
+
+ eglDestroySyncKHR(display, fence);
+ }
+ return true;
+ }
+
+ renderthread::EglManager mEglManager;
+};
+
+class VkUploader : public AHBUploader {
+private:
+ void onInitialize() override {
+ std::lock_guard _lock{mLock};
+ if (!mUploadThread) {
+ mUploadThread = new ThreadBase{};
+ }
+ if (!mUploadThread->isRunning()) {
+ mUploadThread->start("GrallocUploadThread");
+ }
+
+ mUploadThread->queue().post([this]() {
+ std::lock_guard _lock{mVkLock};
+ if (!mVulkanManager.hasVkContext()) {
+ mVulkanManager.initialize();
+ }
});
- sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
}
-}
+ void onDestroy() override {
+ mGrContext.reset();
+ mVulkanManager.destroy();
+ }
+ void onIdle() override {
+ mGrContext.reset();
+ }
-static void endUpload() {
- std::lock_guard _lock{sLock};
- sPendingUploads--;
- sLastUpload = systemTime();
-}
+ void onBeginUpload() override {
+ {
+ std::lock_guard _lock{mVkLock};
+ if (!mVulkanManager.hasVkContext()) {
+ LOG_ALWAYS_FATAL_IF(mGrContext,
+ "GrContext exists with no VulkanManager for vulkan uploads");
+ mUploadThread->queue().runSync([this]() {
+ mVulkanManager.initialize();
+ });
+ }
+ }
+ if (!mGrContext) {
+ GrContextOptions options;
+ mGrContext = mVulkanManager.createContext(options);
+ LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+ this->postIdleTimeoutCheck();
+ }
+ }
-static EGLDisplay getUploadEglDisplay() {
- std::lock_guard _lock{sLock};
- LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
- return sEglManager.eglDisplay();
-}
+ bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) override {
+ ATRACE_CALL();
+
+ std::lock_guard _lock{mLock};
+
+ sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(),
+ bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()));
+ return (image.get() != nullptr);
+ }
+
+ sk_sp<GrContext> mGrContext;
+ renderthread::VulkanManager mVulkanManager;
+ std::mutex mVkLock;
+};
bool HardwareBitmapUploader::hasFP16Support() {
static std::once_flag sOnce;
@@ -105,16 +297,7 @@
return hasFP16Support;
}
-#define FENCE_TIMEOUT 2000000000
-
-struct FormatInfo {
- PixelFormat pixelFormat;
- GLint format, type;
- bool isSupported = false;
- bool valid = true;
-};
-
-static FormatInfo determineFormat(const SkBitmap& skBitmap) {
+static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
case kRGBA_8888_SkColorType:
@@ -124,15 +307,18 @@
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_RGBA;
formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
break;
case kRGBA_F16_SkColorType:
formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
if (formatInfo.isSupported) {
formatInfo.type = GL_HALF_FLOAT;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+ formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
} else {
formatInfo.type = GL_UNSIGNED_BYTE;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
}
formatInfo.format = GL_RGBA;
break;
@@ -141,12 +327,14 @@
formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
formatInfo.format = GL_RGB;
formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
+ formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
case kGray_8_SkColorType:
- formatInfo.isSupported = true;
+ formatInfo.isSupported = usingGL;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_LUMINANCE;
formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
@@ -172,29 +360,37 @@
}
}
-class ScopedUploadRequest {
-public:
- ScopedUploadRequest() { beginUpload(); }
- ~ScopedUploadRequest() { endUpload(); }
-};
+
+static void createUploader(bool usingGL) {
+ static std::mutex lock;
+ std::lock_guard _lock{lock};
+ if (!sUploader.get()) {
+ if (usingGL) {
+ sUploader = new EGLUploader();
+ } else {
+ sUploader = new VkUploader();
+ }
+ }
+}
sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
ATRACE_CALL();
- FormatInfo format = determineFormat(sourceBitmap);
+ bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL;
+
+ FormatInfo format = determineFormat(sourceBitmap, usingGL);
if (!format.valid) {
return nullptr;
}
- ScopedUploadRequest _uploadRequest{};
-
SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
sp<GraphicBuffer> buffer = new GraphicBuffer(
static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
format.pixelFormat,
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+ std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) +
"]");
status_t error = buffer->initCheck();
@@ -203,64 +399,24 @@
return nullptr;
}
- EGLDisplay display = getUploadEglDisplay();
+ createUploader(usingGL);
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
- // We use an EGLImage to access the content of the GraphicBuffer
- // The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
- AutoEglImage autoImage(display, clientBuffer);
- if (autoImage.image == EGL_NO_IMAGE_KHR) {
- ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) {
return nullptr;
}
-
- {
- ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
- EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR {
- AutoSkiaGlTexture glTexture;
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
- GL_CHECKPOINT(MODERATE);
-
- // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
- // provide.
- // But asynchronous in sense that driver may upload texture onto hardware buffer when we
- // first
- // use it in drawing
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
- format.type, bitmap.getPixels());
- GL_CHECKPOINT(MODERATE);
-
- EGLSyncKHR uploadFence =
- eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
- LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
- eglGetError());
- glFlush();
- return uploadFence;
- });
-
- EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
- LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
- "Failed to wait for the fence %#x", eglGetError());
-
- eglDestroySyncKHR(display, fence);
- }
-
- return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+ return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(),
bitmap.alphaType(), Bitmap::computePalette(bitmap));
}
+void HardwareBitmapUploader::initialize() {
+ bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL;
+ createUploader(usingGL);
+ sUploader->initialize();
+}
+
void HardwareBitmapUploader::terminate() {
- std::lock_guard _lock{sLock};
- LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
- if (sUploadThread) {
- sUploadThread->requestExit();
- sUploadThread->join();
- sUploadThread = nullptr;
- }
- sEglManager.destroy();
+ sUploader->destroy();
}
} // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6f41e6d..c300593 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -22,9 +22,11 @@
class ANDROID_API HardwareBitmapUploader {
public:
- static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+ static void initialize();
static void terminate();
+ static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+
static bool hasFP16Support();
};
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index def805a..6cce319 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -29,6 +29,7 @@
#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
+#include "../HardwareBitmapUploader.h"
#ifdef HWUI_GLES_WRAP_ENABLED
#include "debug/GlesDriver.h"
@@ -415,6 +416,7 @@
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
requireVkContext();
}
+ HardwareBitmapUploader::initialize();
}
} /* namespace renderthread */
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6a595d2..f9080a7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1820,6 +1820,21 @@
"android.media.action.MICROPHONE_MUTE_CHANGED";
/**
+ * Broadcast Action: speakerphone state changed.
+ *
+ * You <em>cannot</em> receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+ * Context.registerReceiver()}.
+ *
+ * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
+ * speakerphone functionality is enabled or not.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
+ "android.media.action.SPEAKERPHONE_STATE_CHANGED";
+
+ /**
* Sets the audio mode.
* <p>
* The audio mode encompasses audio routing AND the behavior of
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index cfcc294..02348476 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -22,10 +22,10 @@
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
import android.media.session.ISession2TokensListener;
import android.media.session.MediaSession;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.os.Bundle;
import android.view.KeyEvent;
@@ -34,7 +34,7 @@
* @hide
*/
interface ISessionManager {
- SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
+ ISession createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
in Bundle sessionInfo, int userId);
void notifySession2Created(in Session2Token sessionToken);
List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 4fc436c..cbc6c9d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,6 +36,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.MediaBrowserService;
import android.text.TextUtils;
@@ -163,11 +164,11 @@
.getSystemService(Context.MEDIA_SESSION_SERVICE);
try {
SessionCallbackLink cbLink = new SessionCallbackLink(context);
- SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
- mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
+ ISession binder = manager.createSession(cbLink, tag, sessionInfo);
+ mImpl = new MediaSessionEngine(context, binder, cbLink);
mMaxBitmapSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
throw new RuntimeException("Remote error creating session.", e);
}
}
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
index 266bf32..7c5243a 100644
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -25,6 +25,7 @@
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.MediaSessionManager.RemoteUserInfo;
@@ -34,6 +35,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.MediaBrowserService;
import android.text.TextUtils;
@@ -55,7 +57,7 @@
private final MediaSession.Token mSessionToken;
private final MediaController mController;
- private final SessionLink mSessionLink;
+ private final ISession mBinder;
private CallbackMessageHandler mCallbackHandler;
private VolumeProvider mVolumeProvider;
@@ -70,14 +72,14 @@
* finished with the session.
*
* @param context The context to use to create the session.
- * @param sessionLink A session link for the binder of MediaSessionRecord
+ * @param binder A session binder
*/
- public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
- @NonNull SessionCallbackLink cbLink) {
- mSessionLink = sessionLink;
+ public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder,
+ @NonNull SessionCallbackLink cbLink) throws RemoteException {
+ mBinder = binder;
cbLink.setSessionEngine(this);
- mSessionToken = new MediaSession.Token(mSessionLink.getController());
+ mSessionToken = new MediaSession.Token(mBinder.getController());
mController = new MediaController(context, mSessionToken);
}
@@ -134,8 +136,8 @@
*/
public void setSessionActivity(@Nullable PendingIntent pi) {
try {
- mSessionLink.setLaunchPendingIntent(pi);
- } catch (RuntimeException e) {
+ mBinder.setLaunchPendingIntent(pi);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
}
}
@@ -150,8 +152,8 @@
*/
public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
try {
- mSessionLink.setMediaButtonReceiver(mbr);
- } catch (RuntimeException e) {
+ mBinder.setMediaButtonReceiver(mbr);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
}
}
@@ -163,8 +165,8 @@
*/
public void setFlags(int flags) {
try {
- mSessionLink.setFlags(flags);
- } catch (RuntimeException e) {
+ mBinder.setFlags(flags);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setFlags.", e);
}
}
@@ -185,8 +187,8 @@
throw new IllegalArgumentException("Attributes cannot be null for local playback.");
}
try {
- mSessionLink.setPlaybackToLocal(attributes);
- } catch (RuntimeException e) {
+ mBinder.setPlaybackToLocal(attributes);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
}
}
@@ -217,10 +219,10 @@
});
try {
- mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+ mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
volumeProvider.getMaxVolume());
- mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume());
- } catch (RuntimeException e) {
+ mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
}
}
@@ -238,9 +240,9 @@
return;
}
try {
- mSessionLink.setActive(active);
+ mBinder.setActive(active);
mActive = active;
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setActive.", e);
}
}
@@ -267,8 +269,8 @@
throw new IllegalArgumentException("event cannot be null or empty");
}
try {
- mSessionLink.sendEvent(event, extras);
- } catch (RuntimeException e) {
+ mBinder.sendEvent(event, extras);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error sending event", e);
}
}
@@ -280,8 +282,8 @@
*/
public void close() {
try {
- mSessionLink.destroySession();
- } catch (RuntimeException e) {
+ mBinder.destroySession();
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error releasing session: ", e);
}
}
@@ -316,8 +318,8 @@
public void setPlaybackState(@Nullable PlaybackState state) {
mPlaybackState = state;
try {
- mSessionLink.setPlaybackState(state);
- } catch (RuntimeException e) {
+ mBinder.setPlaybackState(state);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Dead object in setPlaybackState.", e);
}
}
@@ -344,8 +346,8 @@
String metadataDescription = "size=" + fields + ", description=" + description;
try {
- mSessionLink.setMetadata(metadata, duration, metadataDescription);
- } catch (RuntimeException e) {
+ mBinder.setMetadata(metadata, duration, metadataDescription);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Dead object in setPlaybackState.", e);
}
}
@@ -363,8 +365,8 @@
*/
public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
try {
- mSessionLink.setQueue(queue);
- } catch (RuntimeException e) {
+ mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+ } catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
}
@@ -378,8 +380,8 @@
*/
public void setQueueTitle(@Nullable CharSequence title) {
try {
- mSessionLink.setQueueTitle(title);
- } catch (RuntimeException e) {
+ mBinder.setQueueTitle(title);
+ } catch (RemoteException e) {
Log.wtf("Dead object in setQueueTitle.", e);
}
}
@@ -399,8 +401,8 @@
*/
public void setRatingType(int type) {
try {
- mSessionLink.setRatingType(type);
- } catch (RuntimeException e) {
+ mBinder.setRatingType(type);
+ } catch (RemoteException e) {
Log.e(TAG, "Error in setRatingType.", e);
}
}
@@ -414,8 +416,8 @@
*/
public void setExtras(@Nullable Bundle extras) {
try {
- mSessionLink.setExtras(extras);
- } catch (RuntimeException e) {
+ mBinder.setExtras(extras);
+ } catch (RemoteException e) {
Log.wtf("Dead object in setExtras.", e);
}
}
@@ -464,8 +466,8 @@
}
}
try {
- mSessionLink.setCurrentVolume(provider.getCurrentVolume());
- } catch (RuntimeException e) {
+ mBinder.setCurrentVolume(provider.getCurrentVolume());
+ } catch (RemoteException e) {
Log.e(TAG, "Error in notifyVolumeChanged", e);
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f530442..7ca5c93 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -107,7 +107,7 @@
* @hide
*/
@NonNull
- public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
+ public ISession createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
@Nullable Bundle sessionInfo) {
try {
return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo,
diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java
deleted file mode 100644
index a47c262..0000000
--- a/media/java/android/media/session/SessionLink.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 2019 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.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession.QueueItem;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Handles incoming commands from {@link MediaSession}.
- * @hide
- */
-public final class SessionLink implements Parcelable {
- public static final @android.annotation.NonNull Parcelable.Creator<SessionLink> CREATOR =
- new Parcelable.Creator<SessionLink>() {
- @Override
- public SessionLink createFromParcel(Parcel in) {
- return new SessionLink(in.readStrongBinder());
- }
-
- @Override
- public SessionLink[] newArray(int size) {
- return new SessionLink[size];
- }
- };
-
- final SessionStub mSessionStub;
- final ISession mISession;
-
- /**
- * Constructor for stub (Callee)
- */
- public SessionLink(@NonNull SessionStub sessionStub) {
- mSessionStub = sessionStub;
- mISession = new StubProxy();
- }
-
- /**
- * Constructor for interface (Caller)
- */
- public SessionLink(IBinder binder) {
- mSessionStub = null;
- mISession = ISession.Stub.asInterface(binder);
- }
-
- /**
- * Tell system that the session sends an event to all the connected controllers.
- *
- * @param event the name of the event
- * @param extras the extras included with the event
- */
- void sendEvent(@NonNull String event, @Nullable Bundle extras) {
- try {
- mISession.sendEvent(event, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the controller binder from the system.
- */
- @NonNull
- ISessionController getController() {
- try {
- return mISession.getController();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the flags.
- *
- * @param flags the new session flags
- */
- void setFlags(int flags) {
- try {
- mISession.setFlags(flags);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session is (in)active.
- *
- * @param active the new activeness state
- */
- void setActive(boolean active) {
- try {
- mISession.setActive(active);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the media button receiver.
- *
- * @param mbr the pending intent for media button receiver
- */
- void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- try {
- mISession.setMediaButtonReceiver(mbr);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the pending intent for launching UI.
- *
- * @param pi the pending intent for launching UI
- */
- void setLaunchPendingIntent(@Nullable PendingIntent pi) {
- try {
- mISession.setLaunchPendingIntent(pi);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session is destroyed.
- */
- void destroySession() {
- try {
- mISession.destroySession();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new metadata.
- *
- * @param metadata the new metadata
- * @param duration the duration of the media in milliseconds
- * @param metadataDescription the description of the metadata
- */
- void setMetadata(@Nullable MediaMetadata metadata, long duration,
- @Nullable String metadataDescription) {
- try {
- mISession.setMetadata(metadata, duration, metadataDescription);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new playback state.
- *
- * @param state the new playback state
- */
- void setPlaybackState(@Nullable PlaybackState state) {
- try {
- mISession.setPlaybackState(state);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new queue.
- *
- * @param queue the new queue
- */
- void setQueue(@Nullable List<QueueItem> queue) {
- try {
- mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new queue title.
- *
- * @param title the new queue title
- */
- void setQueueTitle(@Nullable CharSequence title) {
- try {
- mISession.setQueueTitle(title);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new extras.
- *
- * @param extras the new extras
- */
- void setExtras(@Nullable Bundle extras) {
- try {
- mISession.setExtras(extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new rating type of the current media.
- *
- * @param type the rating type.
- */
- void setRatingType(int type) {
- try {
- mISession.setRatingType(type);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session represents a local playback.
- *
- * @param attributes the audio attributes of the local playback.
- */
- void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
- try {
- mISession.setPlaybackToLocal(attributes);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session represents a remote playback.
- *
- * @param control the volume control type
- * @param max the max volume
- */
- void setPlaybackToRemote(int control, int max) {
- try {
- mISession.setPlaybackToRemote(control, max);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new current volume.
- *
- * @param currentVolume the new current volume
- */
- void setCurrentVolume(int currentVolume) {
- try {
- mISession.setCurrentVolume(currentVolume);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Gets the binder */
- @NonNull
- public IBinder getBinder() {
- return mISession.asBinder();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mISession.asBinder());
- }
-
- /**
- * Class for Stub implementation
- */
- public abstract static class SessionStub {
- /** Stub method for ISession.sendEvent */
- public void sendEvent(@NonNull String event, @Nullable Bundle data) {
- }
-
- /** Stub method for ISession.getController */
- @NonNull
- public ISessionController getController() {
- return null;
- }
-
- /** Stub method for ISession.setFlags */
- public void setFlags(int flags) {
- }
-
- /** Stub method for ISession.setActive */
- public void setActive(boolean active) {
- }
-
- /** Stub method for ISession.setMediaButtonReceiver */
- public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- }
-
- /** Stub method for ISession.setLaunchPendingIntent */
- public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
- }
-
- /** Stub method for ISession.destroySession */
- public void destroySession() {
- }
-
- /** Stub method for ISession.setMetadata */
- public void setMetadata(@Nullable MediaMetadata metadata, long duration,
- @Nullable String metadataDescription) {
- }
-
- /** Stub method for ISession.setPlaybackState */
- public void setPlaybackState(@Nullable PlaybackState state) {
- }
-
- /** Stub method for ISession.setQueue */
- public void setQueue(@Nullable List<QueueItem> queue) {
- }
-
- /** Stub method for ISession.setQueueTitle */
- public void setQueueTitle(@Nullable CharSequence title) {
- }
-
- /** Stub method for ISession.setExtras */
- public void setExtras(@Nullable Bundle extras) {
- }
-
- /** Stub method for ISession.setRatingType */
- public void setRatingType(int type) {
- }
-
- /** Stub method for ISession.setPlaybackToLocal */
- public void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
- }
-
- /** Stub method for ISession.setPlaybackToRemote */
- public void setPlaybackToRemote(int control, int max) {
- }
-
- /** Stub method for ISession.setCurrentVolume */
- public void setCurrentVolume(int currentVolume) {
- }
- }
-
- private class StubProxy extends ISession.Stub {
- @Override
- public void sendEvent(String event, Bundle data) {
- mSessionStub.sendEvent(event, data);
- }
-
- @Override
- public ISessionController getController() {
- return mSessionStub.getController();
- }
-
- @Override
- public void setFlags(int flags) {
- mSessionStub.setFlags(flags);
- }
-
- @Override
- public void setActive(boolean active) {
- mSessionStub.setActive(active);
- }
-
- @Override
- public void setMediaButtonReceiver(PendingIntent mbr) {
- mSessionStub.setMediaButtonReceiver(mbr);
- }
-
- @Override
- public void setLaunchPendingIntent(PendingIntent pi) {
- mSessionStub.setLaunchPendingIntent(pi);
- }
-
- @Override
- public void destroySession() {
- mSessionStub.destroySession();
- }
-
- @Override
- public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
- mSessionStub.setMetadata(metadata, duration, metadataDescription);
- }
-
- @Override
- public void setPlaybackState(PlaybackState state) {
- mSessionStub.setPlaybackState(state);
- }
-
- @Override
- public void setQueue(MediaParceledListSlice queue) {
- mSessionStub.setQueue(queue == null ? null : queue.getList());
- }
-
- @Override
- public void setQueueTitle(CharSequence title) {
- mSessionStub.setQueueTitle(title);
- }
-
- @Override
- public void setExtras(Bundle extras) {
- mSessionStub.setExtras(extras);
- }
-
- @Override
- public void setRatingType(int type) {
- mSessionStub.setRatingType(type);
- }
-
- @Override
- public void setPlaybackToLocal(AudioAttributes attributes) {
- mSessionStub.setPlaybackToLocal(attributes);
- }
-
- @Override
- public void setPlaybackToRemote(int control, int max) {
- mSessionStub.setPlaybackToRemote(control, max);
- }
-
- @Override
- public void setCurrentVolume(int currentVolume) {
- mSessionStub.setCurrentVolume(currentVolume);
- }
- }
-}
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9064ebe..4c9629d 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -58,8 +58,8 @@
manifest: "AndroidManifest.xml",
- owner: "google",
platform_apis: true,
+ product_specific: true,
certificate: "platform",
privileged: true,
@@ -82,4 +82,6 @@
],
plugins: ["dagger2-compiler-2.19"],
+
+ required: ["privapp_whitelist_com.android.systemui"],
}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 190247a..8872147 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -25,6 +25,7 @@
":services-networkstack-shared-srcs",
],
static_libs: [
+ "ipmemorystore-client",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
"datastallprotosnano",
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
index a8c712a..7346b1a 100644
--- a/packages/NetworkStack/jarjar-rules-shared.txt
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -8,12 +8,3 @@
rule android.net.DhcpResultsParcelable* @0
rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
rule android.net.LocalLog* android.net.networkstack.LocalLog@1
-
-# TODO: remove from framework dependencies, then remove here
-rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
-rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
-
-# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
-rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
-# TODO: move TcpKeepalivePacketData to services.net and delete
-rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
new file mode 100644
index 0000000..475f826
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in the same module.
+ * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+public class NetworkStackIpMemoryStore extends IpMemoryStoreClient {
+ @NonNull private final IIpMemoryStore mService;
+
+ public NetworkStackIpMemoryStore(@NonNull final Context context,
+ @NonNull final IIpMemoryStore service) {
+ super(context);
+ mService = service;
+ }
+
+ @Override
+ @NonNull
+ protected IIpMemoryStore getService() {
+ return mService;
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 7c7cdbd..b68fe23 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,6 +29,7 @@
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStackIpMemoryStore;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
import android.net.RouteInfo;
@@ -61,6 +62,7 @@
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService.NetworkStackServiceManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -100,6 +102,7 @@
// One holds StateMachine logs and the other connectivity packet logs.
private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+ private final NetworkStackIpMemoryStore mIpMemoryStore;
/**
* Dump all state machine and connectivity packet logs to the specified writer.
@@ -388,13 +391,14 @@
}
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
- NetworkObserverRegistry observerRegistry) {
- this(context, ifName, callback, observerRegistry, new Dependencies());
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
+ this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
}
@VisibleForTesting
IpClient(Context context, String ifName, IIpClientCallbacks callback,
- NetworkObserverRegistry observerRegistry, Dependencies deps) {
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
+ Dependencies deps) {
super(IpClient.class.getSimpleName() + "." + ifName);
Preconditions.checkNotNull(ifName);
Preconditions.checkNotNull(callback);
@@ -408,6 +412,8 @@
mShutdownLatch = new CountDownLatch(1);
mCm = mContext.getSystemService(ConnectivityManager.class);
mObserverRegistry = observerRegistry;
+ mIpMemoryStore =
+ new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
mLog = sSmLogs.get(mInterfaceName);
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index e7c8e85..335d951 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -29,6 +29,8 @@
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.IIpMemoryStore;
+import android.net.IIpMemoryStoreCallbacks;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
@@ -49,6 +51,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -86,7 +89,19 @@
return makeConnector(this);
}
- private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+ /**
+ * An interface for internal clients of the network stack service that can return
+ * or create inline instances of the service it manages.
+ */
+ public interface NetworkStackServiceManager {
+ /**
+ * Get an instance of the IpMemoryStoreService.
+ */
+ IIpMemoryStore getIpMemoryStoreService();
+ }
+
+ private static class NetworkStackConnector extends INetworkStackConnector.Stub
+ implements NetworkStackServiceManager {
private static final int NUM_VALIDATION_LOG_LINES = 20;
private final Context mContext;
private final INetd mNetd;
@@ -94,6 +109,7 @@
private final ConnectivityManager mCm;
@GuardedBy("mIpClients")
private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
+ private final IpMemoryStoreService mIpMemoryStoreService;
private static final int MAX_VALIDATION_LOGS = 10;
@GuardedBy("mValidationLogs")
@@ -116,6 +132,7 @@
(IBinder) context.getSystemService(Context.NETD_SERVICE));
mObserverRegistry = new NetworkObserverRegistry();
mCm = context.getSystemService(ConnectivityManager.class);
+ mIpMemoryStoreService = new IpMemoryStoreService(context);
try {
mObserverRegistry.register(mNetd);
@@ -159,7 +176,7 @@
@Override
public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
- final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
+ final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this);
synchronized (mIpClients) {
final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
@@ -176,6 +193,17 @@
}
@Override
+ public IIpMemoryStore getIpMemoryStoreService() {
+ return mIpMemoryStoreService;
+ }
+
+ @Override
+ public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb)
+ throws RemoteException {
+ cb.onIpMemoryStoreFetched(mIpMemoryStoreService);
+ }
+
+ @Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
checkDumpPermission();
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index b238ae4..9d91487 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -1615,12 +1615,12 @@
return;
}
// See if the data sub is registered for PS services on cell.
- final NetworkRegistrationInfo nrs = dataSs.getNetworkRegistrationInfo(
+ final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS,
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
latencyBroadcast.putExtra(
NetworkMonitorUtils.EXTRA_CELL_ID,
- nrs == null ? null : nrs.getCellIdentity());
+ nri == null ? null : nri.getCellIdentity());
latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
} else {
return;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index bbecc63..4d4ceed 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
similarity index 98%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index d43dc6a..f801b35 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
import static android.net.ipmemorystore.Status.ERROR_GENERIC;
import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
import static android.net.ipmemorystore.Status.SUCCESS;
-import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,7 +40,6 @@
import android.net.ipmemorystore.SameL3NetworkResponse;
import android.net.ipmemorystore.Status;
import android.net.ipmemorystore.StatusParcelable;
-import android.net.ipmemorystore.Utils;
import android.os.RemoteException;
import android.util.Log;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
index aa45400..38d5544 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
similarity index 94%
rename from core/java/android/net/ipmemorystore/Utils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
index b361aca..9cbf490 100644
--- a/core/java/android/net/ipmemorystore/Utils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.ipmemorystore.Blob;
/** {@hide} */
public class Utils {
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 4536c47..eee12d6 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -51,6 +51,7 @@
import com.android.internal.R;
import com.android.server.NetworkObserver;
import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService;
import org.junit.Before;
import org.junit.Test;
@@ -90,6 +91,7 @@
@Mock private AlarmManager mAlarm;
@Mock private IpClient.Dependencies mDependencies;
@Mock private ContentResolver mContentResolver;
+ @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
private NetworkObserver mObserver;
private InterfaceParams mIfParams;
@@ -118,7 +120,8 @@
private IpClient makeIpClient(String ifname) throws Exception {
setTestInterfaceParams(ifname);
- final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
@@ -142,8 +145,8 @@
public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
setTestInterfaceParams(null);
try {
- final IpClient ipc = new IpClient(
- mContext, null, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -156,8 +159,8 @@
final String ifname = "lo";
setTestInterfaceParams(ifname);
try {
- final IpClient ipc = new IpClient(
- mContext, ifname, null, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -168,16 +171,16 @@
@Test
public void testInvalidInterfaceDoesNotThrow() throws Exception {
setTestInterfaceParams(TEST_IFNAME);
- final IpClient ipc = new IpClient(
- mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
}
@Test
public void testInterfaceNotFoundFailsImmediately() throws Exception {
setTestInterfaceParams(null);
- final IpClient ipc = new IpClient(
- mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.startProvisioning(new ProvisioningConfiguration());
verify(mCb, times(1)).onProvisioningFailure(any());
ipc.shutdown();
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
similarity index 99%
rename from tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index be10680..d0e58b8 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
similarity index 97%
rename from tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
index 7413b914..3d3aabc 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
-import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index e27ae7d..da575db 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -21,6 +21,8 @@
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="horizontal">
<LinearLayout
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index c9fbc7b..d4d0519 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -128,12 +128,12 @@
// to protect access to these.
final ArrayList<Session> mSessions = new ArrayList<Session>();
final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
- final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
+ private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
// Map: userid => (Map: package name => AppEntry)
final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
new SparseArray<HashMap<String, AppEntry>>();
final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
- List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>();
+ List<ApplicationInfo> mApplications = new ArrayList<>();
long mCurId = 1;
UUID mCurComputingSizeUuid;
String mCurComputingSizePkg;
@@ -166,7 +166,7 @@
/**
* Flags to configure the session to request various types of info.
*/
- @IntDef(prefix = { "FLAG_SESSION_" }, value = {
+ @IntDef(prefix = {"FLAG_SESSION_"}, value = {
FLAG_SESSION_REQUEST_HOME_APP,
FLAG_SESSION_REQUEST_ICONS,
FLAG_SESSION_REQUEST_SIZES,
@@ -174,7 +174,13 @@
FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER
})
@Retention(RetentionPolicy.SOURCE)
- public @interface SessionFlags {}
+ public @interface SessionFlags {
+ }
+
+ @VisibleForTesting
+ void setInterestingConfigChanges(InterestingConfigChanges interestingConfigChanges) {
+ mInterestingConfigChanges = interestingConfigChanges;
+ }
public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
@@ -190,6 +196,7 @@
for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
mEntriesMap.put(userId, new HashMap<String, AppEntry>());
}
+
mThread = new HandlerThread("ApplicationsState.Loader",
Process.THREAD_PRIORITY_BACKGROUND);
mThread.start();
@@ -256,12 +263,14 @@
mPackageIntentReceiver = new PackageIntentReceiver();
mPackageIntentReceiver.registerReceiver();
}
- mApplications = new ArrayList<ApplicationInfo>();
+
+ final List<ApplicationInfo> prevApplications = mApplications;
+ mApplications = new ArrayList<>();
for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
try {
// If this user is new, it needs a map created.
if (mEntriesMap.indexOfKey(user.id) < 0) {
- mEntriesMap.put(user.id, new HashMap<String, AppEntry>());
+ mEntriesMap.put(user.id, new HashMap<>());
}
@SuppressWarnings("unchecked")
ParceledListSlice<ApplicationInfo> list =
@@ -279,14 +288,14 @@
// should completely reload the app entries.
clearEntries();
} else {
- for (int i=0; i<mAppEntries.size(); i++) {
+ for (int i = 0; i < mAppEntries.size(); i++) {
mAppEntries.get(i).sizeStale = true;
}
}
mHaveDisabledApps = false;
mHaveInstantApps = false;
- for (int i=0; i<mApplications.size(); i++) {
+ for (int i = 0; i < mApplications.size(); i++) {
final ApplicationInfo info = mApplications.get(i);
// Need to trim out any applications that are disabled by
// something different than the user.
@@ -312,8 +321,9 @@
entry.info = info;
}
}
- if (mAppEntries.size() > mApplications.size()) {
- // There are less apps now, some must have been uninstalled.
+
+ if (anyAppIsRemoved(prevApplications, mApplications)) {
+ // some apps have been uninstalled.
clearEntries();
}
mCurComputingSizePkg = null;
@@ -322,6 +332,82 @@
}
}
+ /* The original design is mAppEntries.size() > mApplications.size().
+ It's correct if there is only the owner user and only one app is removed.
+ Problem 1:
+ If there is a user profile, the size of mAppEntries < mApplications is normal because
+ the number of app entries on UI (mAppEntries) should be equal to the number of apps got
+ from PMS (mApplications).
+
+ owner only case:
+ mApplications: user 0: 191
+ mAppEntries : user 0: 191
+ total mAppEntries: 191, mApplications: 191
+ If an app is removed, cached mAppEntries: 191 , mApplications: 191 -> 190, it is detected
+ as the number of apps becomes less.
+
+ If there is a work profile, mAppEntries removes some apps that are not installed for the
+ owner user.
+
+ For example, in the following case, 6 apps are removed from mAppEntries for the owner.
+ mApplications: user 0: 197, user 10: 189 => total 386
+ mAppEntries : user 0: 191, user 10: 189 => total 380
+ If an app is removed, cached mAppEntries: 380 , mApplications: 386 -> 385, the size of
+ mAppEntries is still not larger than mApplications, then does not clear mAppEntries.
+
+ Problem 2:
+ If remove an app and add another app outside Settings (e.g. Play Store) and back to
+ Settings, the amount of apps are not changed, it causes the entries keep the removed app.
+
+ Another case, if adding more apps than removing apps (e.g. add 2 apps and remove 1 app),
+ the final number of apps (mApplications) is even increased,
+
+ Therefore, should not only count on number of apps to determine any app is removed.
+ Compare the change of applications instead.
+ */
+ private static boolean anyAppIsRemoved(List<ApplicationInfo> prevApplications,
+ List<ApplicationInfo> applications) {
+
+ // No cache
+ if (prevApplications.size() == 0) {
+ return false;
+ }
+
+ if (applications.size() < prevApplications.size()) {
+ return true;
+ }
+
+ // build package sets of all applications <userId, HashSet of packages>
+ final HashMap<String, HashSet<String>> packageMap = new HashMap<>();
+ for (ApplicationInfo application : applications) {
+ final String userId = String.valueOf(UserHandle.getUserId(application.uid));
+
+ HashSet<String> appPackages = packageMap.get(userId);
+ if (appPackages == null) {
+ appPackages = new HashSet<>();
+ packageMap.put(userId, appPackages);
+ }
+ if (hasFlag(application.flags, ApplicationInfo.FLAG_INSTALLED)) {
+ appPackages.add(application.packageName);
+ }
+ }
+
+ // detect any previous app is removed
+ for (ApplicationInfo prevApplication : prevApplications) {
+ if (!hasFlag(prevApplication.flags, ApplicationInfo.FLAG_INSTALLED)) {
+ continue;
+ }
+ final String userId = String.valueOf(UserHandle.getUserId(prevApplication.uid));
+
+ final HashSet<String> packagesSet = packageMap.get(userId);
+ if (packagesSet == null || !packagesSet.remove(prevApplication.packageName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@VisibleForTesting
void clearEntries() {
for (int i = 0; i < mEntriesMap.size(); i++) {
@@ -346,7 +432,7 @@
if (!mResumed) {
return;
}
- for (int i=0; i<mSessions.size(); i++) {
+ for (int i = 0; i < mSessions.size(); i++) {
if (mSessions.get(i).mResumed) {
return;
}
@@ -449,7 +535,7 @@
if (DEBUG_LOCKING) Log.v(TAG, "sumCacheSizes about to acquire lock...");
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "-> sumCacheSizes now has lock");
- for (int i=mAppEntries.size()-1; i>=0; i--) {
+ for (int i = mAppEntries.size() - 1; i >= 0; i--) {
sum += mAppEntries.get(i).cacheSize;
}
if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock");
@@ -458,7 +544,7 @@
}
int indexOfApplicationInfoLocked(String pkgName, int userId) {
- for (int i=mApplications.size()-1; i>=0; i--) {
+ for (int i = mApplications.size() - 1; i >= 0; i--) {
ApplicationInfo appInfo = mApplications.get(i);
if (appInfo.packageName.equals(pkgName)
&& UserHandle.getUserId(appInfo.uid) == userId) {
@@ -642,7 +728,7 @@
return;
}
mActiveSessions.clear();
- for (int i=0; i<mSessions.size(); i++) {
+ for (int i = 0; i < mSessions.size(); i++) {
Session s = mSessions.get(i);
if (s.mResumed) {
mActiveSessions.add(new WeakReference<>(s));
@@ -784,7 +870,7 @@
ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
if (DEBUG) Log.i(TAG, "Rebuilding...");
- for (int i=0; i<apps.size(); i++) {
+ for (int i = 0; i < apps.size(); i++) {
AppEntry entry = apps.get(i);
if (entry != null && (filter == null || filter.filterApp(entry))) {
synchronized (mEntriesMap) {
@@ -954,7 +1040,7 @@
}
}
if (rebuildingSessions != null) {
- for (int i=0; i<rebuildingSessions.size(); i++) {
+ for (int i = 0; i < rebuildingSessions.size(); i++) {
rebuildingSessions.get(i).handleRebuildList();
}
}
@@ -1047,9 +1133,9 @@
// If we do not specify MATCH_DIRECT_BOOT_AWARE or
// MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
// according to the user's lock state. When the user is locked,
- // components
- // with ComponentInfo#directBootAware == false will be filtered. We should
- // explicitly include both direct boot aware and unaware components here.
+ // components with ComponentInfo#directBootAware == false will be
+ // filtered. W should explicitly include both direct boot aware and
+ // unaware component here.
List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
launchIntent,
PackageManager.MATCH_DISABLED_COMPONENTS
@@ -1128,8 +1214,10 @@
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock");
if (mCurComputingSizePkg != null) {
- if (DEBUG_LOCKING) Log.v(TAG,
- "MSG_LOAD_SIZES releasing: currently computing");
+ if (DEBUG_LOCKING) {
+ Log.v(TAG,
+ "MSG_LOAD_SIZES releasing: currently computing");
+ }
return;
}
@@ -1181,8 +1269,10 @@
});
}
- if (DEBUG_LOCKING) Log.v(TAG,
- "MSG_LOAD_SIZES releasing: now computing");
+ if (DEBUG_LOCKING) {
+ Log.v(TAG,
+ "MSG_LOAD_SIZES releasing: now computing");
+ }
return;
}
}
@@ -1255,8 +1345,10 @@
entry.internalSizeStr = getSizeStr(entry.internalSize);
entry.externalSize = getTotalExternalSize(stats);
entry.externalSizeStr = getSizeStr(entry.externalSize);
- if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry
- + ": " + entry.sizeStr);
+ if (DEBUG) {
+ Log.i(TAG, "Set size of " + entry.label + " " + entry
+ + ": " + entry.sizeStr);
+ }
sizeChanged = true;
}
}
@@ -1299,9 +1391,11 @@
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(this, userFilter);
}
+
void unregisterReceiver() {
mContext.unregisterReceiver(this);
}
+
@Override
public void onReceive(Context context, Intent intent) {
String actionStr = intent.getAction();
@@ -1354,12 +1448,19 @@
public interface Callbacks {
void onRunningStateChanged(boolean running);
+
void onPackageListChanged();
+
void onRebuildComplete(ArrayList<AppEntry> apps);
+
void onPackageIconChanged();
+
void onPackageSizeChanged(String packageName);
+
void onAllSizesComputed();
+
void onLauncherInfoChanged();
+
void onLoadEntriesCompleted();
}
@@ -1491,6 +1592,7 @@
*/
public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
private final Collator sCollator = Collator.getInstance();
+
@Override
public int compare(AppEntry object1, AppEntry object2) {
int compareResult = sCollator.compare(object1.label, object2.label);
@@ -1504,6 +1606,7 @@
return compareResult;
}
}
+
return object1.info.uid - object2.info.uid;
}
};
@@ -1540,9 +1643,11 @@
public interface AppFilter {
void init();
+
default void init(Context context) {
init();
}
+
boolean filterApp(AppEntry info);
}
@@ -1697,7 +1802,8 @@
@Override
public boolean filterApp(AppEntry entry) {
return !AppUtils.isInstant(entry.info)
- && hasFlag(entry.info.privateFlags, ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
+ && hasFlag(entry.info.privateFlags,
+ ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
}
};
@@ -1707,7 +1813,7 @@
@Override
public void init(Context context) {
mHidePackageNames = context.getResources()
- .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+ .getStringArray(R.array.config_hideWhenDisabled_packageNames);
}
@Override
@@ -1720,7 +1826,7 @@
if (!entry.info.enabled) {
return false;
} else if (entry.info.enabledSetting ==
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
return false;
}
}
@@ -1798,7 +1904,7 @@
@Override
public boolean filterApp(AppEntry entry) {
boolean isMusicApp;
- synchronized(entry) {
+ synchronized (entry) {
isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO;
}
return isMusicApp;
@@ -1813,7 +1919,7 @@
@Override
public boolean filterApp(AppEntry entry) {
boolean isMovieApp;
- synchronized(entry) {
+ synchronized (entry) {
isMovieApp = entry.info.category == ApplicationInfo.CATEGORY_VIDEO;
}
return isMovieApp;
@@ -1823,7 +1929,8 @@
public static final AppFilter FILTER_PHOTOS =
new AppFilter() {
@Override
- public void init() {}
+ public void init() {
+ }
@Override
public boolean filterApp(AppEntry entry) {
@@ -1838,7 +1945,8 @@
public static final AppFilter FILTER_OTHER_APPS =
new AppFilter() {
@Override
- public void init() {}
+ public void init() {
+ }
@Override
public boolean filterApp(AppEntry entry) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index a098ecc..b27efd0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -16,11 +16,17 @@
package com.android.settingslib.applications;
+import static android.os.UserHandle.MU_ENABLED;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
@@ -40,10 +46,13 @@
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
@@ -70,6 +79,7 @@
import org.robolectric.shadows.ShadowLooper;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@@ -82,6 +92,19 @@
private final static String HOME_PACKAGE_NAME = "com.android.home";
private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable";
+ private static final int PROFILE_USERID = 10;
+
+ private static final String PKG_1 = "PKG1";
+ private static final int OWNER_UID_1 = 1001;
+ private static final int PROFILE_UID_1 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_1);
+
+ private static final String PKG_2 = "PKG2";
+ private static final int OWNER_UID_2 = 1002;
+ private static final int PROFILE_UID_2 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_2);
+
+ private static final String PKG_3 = "PKG3";
+ private static final int OWNER_UID_3 = 1003;
+
/** Class under test */
private ApplicationsState mApplicationsState;
private Session mSession;
@@ -171,7 +194,7 @@
storageStats.dataBytes = 20;
storageStats.cacheBytes = 30;
when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
- anyString(), any(UserHandle.class))).thenReturn(storageStats);
+ anyString(), any(UserHandle.class))).thenReturn(storageStats);
// Set up 3 installed apps, in which 1 is hidden module
final List<ApplicationInfo> infos = new ArrayList<>();
@@ -195,11 +218,16 @@
}
private ApplicationInfo createApplicationInfo(String packageName) {
+ return createApplicationInfo(packageName, 0);
+ }
+
+ private ApplicationInfo createApplicationInfo(String packageName, int uid) {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.sourceDir = "foo";
appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
appInfo.storageUuid = UUID.randomUUID();
appInfo.packageName = packageName;
+ appInfo.uid = uid;
return appInfo;
}
@@ -211,10 +239,14 @@
}
private void addApp(String packageName, int id) {
- ApplicationInfo appInfo = createApplicationInfo(packageName);
+ addApp(packageName, id, 0);
+ }
+
+ private void addApp(String packageName, int id, int userId) {
+ ApplicationInfo appInfo = createApplicationInfo(packageName, id);
AppEntry appEntry = createAppEntry(appInfo, id);
mApplicationsState.mAppEntries.add(appEntry);
- mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry);
+ mApplicationsState.mEntriesMap.get(userId).put(appInfo.packageName, appEntry);
}
private void processAllMessages() {
@@ -351,4 +383,328 @@
assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
}
+ @Test
+ public void removeAndInstall_noWorkprofile_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ // scenario: only owner user
+ // (PKG_1, PKG_2) -> (PKG_2, PKG_3)
+ // PKG_1 is removed and PKG_3 is installed before app is resumed.
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ // Previous Applications:
+ ApplicationInfo appInfo;
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // (PKG_1, PKG_2)
+ addApp(PKG_1, OWNER_UID_1, 0);
+ addApp(PKG_2, OWNER_UID_2, 0);
+
+ // latest Applications:
+ // (PKG_2, PKG_3)
+ final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_3, OWNER_UID_3);
+ appList.add(appInfo);
+ setupDoResumeIfNeededLocked(appList, null);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void noAppRemoved_noWorkprofile_doResumeIfNeededLocked_shouldNotClearEntries()
+ throws RemoteException {
+ // scenario: only owner user
+ // (PKG_1, PKG_2)
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // (pk1, PKG_2)
+ addApp(PKG_1, OWNER_UID_1, 0);
+ addApp(PKG_2, OWNER_UID_2, 0);
+
+ // latest Applications:
+ // (PKG_2, PKG_3)
+ final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appList.add(appInfo);
+ setupDoResumeIfNeededLocked(appList, null);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState, never()).clearEntries();
+ }
+
+ @Test
+ public void removeProfileApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // [Actions]
+ // profile user's PKG_2 is removed before resume
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2) -> (PKG_1)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1, PKG_2), profile (PKG_1)
+ // owner's PKG_1 is still listed and is in non-installed state
+ // profile user's PKG_2 is removed by a user before resume
+ //owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ ownerAppList.add(appInfo);
+ //profile
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ setupDoResumeIfNeededLocked(ownerAppList, new ArrayList<>(Arrays.asList(appInfo)));
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void removeOwnerApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // [Actions]
+ // Owner user's PKG_2 is removed before resume
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2 - uninstalled)
+ // profile - (PKG_1, PKG_2) -> (PKG_1, PKG_2)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1 - uninstalled, PKG_2 - uninstalled), profile (PKG_1, PKG_2)
+ // owner's PKG_1, PKG_2 is still listed and is in non-installed state
+ // profile user's PKG_2 is removed before resume
+ //owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+
+ //profile
+ final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ profileAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ profileAppList.add(appInfo);
+ setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void noAppRemoved_workprofileExists_doResumeIfNeededLocked_shouldNotClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1 - uninstalled, PKG_2), profile (PKG_1, PKG_2)
+ // owner's PKG_1 is still listed and is in non-installed state
+
+ // owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ ownerAppList.add(appInfo);
+
+ // profile
+ final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ profileAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ profileAppList.add(appInfo);
+ setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState, never()).clearEntries();
+ }
+
+ private void setupDoResumeIfNeededLocked(ArrayList<ApplicationInfo> ownerApps,
+ ArrayList<ApplicationInfo> profileApps)
+ throws RemoteException {
+
+ if (ownerApps != null) {
+ when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(0)))
+ .thenReturn(new ParceledListSlice<>(ownerApps));
+ }
+ if (profileApps != null) {
+ when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(PROFILE_USERID)))
+ .thenReturn(new ParceledListSlice<>(profileApps));
+ }
+ final InterestingConfigChanges configChanges = mock(InterestingConfigChanges.class);
+ when(configChanges.applyNewConfig(any(Resources.class))).thenReturn(false);
+ mApplicationsState.setInterestingConfigChanges(configChanges);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index c50d646..ca1eefc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -29,6 +29,7 @@
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+ private List<UserInfo> mUserInfos = addProfile(0, "Owner");
@Implementation
protected static UserManager get(Context context) {
@@ -37,16 +38,24 @@
@Implementation
protected int[] getProfileIdsWithDisabled(int userId) {
- return new int[]{0};
+ return mUserInfos.stream().mapToInt(s -> s.id).toArray();
}
@Implementation
protected List<UserInfo> getProfiles() {
- UserInfo userInfo = new UserInfo();
- userInfo.id = 0;
- List<UserInfo> userInfos = new ArrayList<>();
- userInfos.add(userInfo);
- return userInfos;
+ return mUserInfos;
+ }
+
+ public List<UserInfo> addProfile(int id, String name) {
+ List<UserInfo> userInfoList = mUserInfos;
+ if (userInfoList == null) {
+ userInfoList = new ArrayList<>();
+ }
+ final UserInfo userInfo = new UserInfo();
+ userInfo.id = id;
+ userInfo.name = name;
+ userInfoList.add(userInfo);
+ return userInfoList;
}
@Implementation
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
index e1bf6cb..5da7611 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -17,15 +17,24 @@
*/
-->
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.keyguard.KeyguardMessageArea
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- style="@style/Keyguard.TextView"
- android:id="@+id/keyguard_message_area"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:focusable="true" />
-
+<!-- This contains error message field and padlock shared by pin/pattern/password screens -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <FrameLayout
+ android:id="@+id/lock_icon_container"
+ android:layout_gravity="center"
+ android:layout_marginBottom="@dimen/keyguard_lock_padding"
+ android:layout_width="@dimen/keyguard_lock_width"
+ android:layout_height="@dimen/keyguard_lock_height" />
+ <com.android.keyguard.KeyguardMessageArea
+ android:id="@+id/keyguard_message_area"
+ style="@style/Keyguard.TextView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:focusable="true" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
index 38d2ecc3..91ca5c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
@@ -21,6 +21,6 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">345dp</dimen>
+ <dimen name="keyguard_security_height">395dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
index 90c4795..d7c9975 100644
--- a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
@@ -21,5 +21,5 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x
keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">400dp</dimen>
+ <dimen name="keyguard_security_height">450dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
index 9ea04dc..a3c37e4 100644
--- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
@@ -20,5 +20,5 @@
<resources>
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">500dp</dimen>
+ <dimen name="keyguard_security_height">550dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 9157822..1dc61c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -20,7 +20,7 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">420dp</dimen>
+ <dimen name="keyguard_security_height">470dp</dimen>
<dimen name="widget_big_font_size">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index b6a41c1..d67c98a 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -27,11 +27,11 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">400dp</dimen>
+ <dimen name="keyguard_security_height">450dp</dimen>
<!-- Max Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_max_height">455dp</dimen>
+ <dimen name="keyguard_security_max_height">505dp</dimen>
<!-- Margin around the various security views -->
<dimen name="keyguard_security_view_top_margin">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 7ed3a80..f07887e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1499,12 +1499,12 @@
private final Context mContext;
private final MyAdapter mAdapter;
private MultiListLayout mGlobalActionsLayout;
- private final Drawable mBackgroundDrawable;
+ private Drawable mBackgroundDrawable;
private final ColorExtractor mColorExtractor;
private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
private boolean mKeyguardShowing;
private boolean mShowing;
- private final float mScrimAlpha;
+ private float mScrimAlpha;
ActionsDialog(Context context, MyAdapter adapter,
GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1531,49 +1531,37 @@
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-
- initializeLayout();
-
setTitle(R.string.global_actions);
mPanelController = plugin;
- View panelView = initializePanel();
- if (panelView == null) {
- mBackgroundDrawable = new GradientDrawable(context);
- mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
- } else {
- mBackgroundDrawable = context.getDrawable(
- com.android.systemui.R.drawable.global_action_panel_scrim);
- mScrimAlpha = 1f;
- addContentView(
- panelView,
- new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
- window.setBackgroundDrawable(mBackgroundDrawable);
+ initializeLayout();
}
- private View initializePanel() {
- if (isPanelEnabled(mContext) && mPanelController != null) {
- View panelView = mPanelController.getPanelContent();
- if (panelView != null) {
- FrameLayout panelContainer = new FrameLayout(mContext);
- FrameLayout.LayoutParams panelParams =
- new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- panelContainer.addView(panelView, panelParams);
- return panelContainer;
- }
+ private boolean initializePanel() {
+ if (!isPanelEnabled(mContext) || mPanelController == null) {
+ return false;
}
- return null;
+ View panelView = mPanelController.getPanelContent();
+ if (panelView == null) {
+ return false;
+ }
+ FrameLayout panelContainer = new FrameLayout(mContext);
+ FrameLayout.LayoutParams panelParams =
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT);
+ panelContainer.addView(panelView, panelParams);
+ addContentView(
+ panelContainer,
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ return true;
}
private void initializeLayout() {
setContentView(getGlobalActionsLayoutId(mContext));
- mGlobalActionsLayout = (MultiListLayout)
- findViewById(com.android.systemui.R.id.global_actions_view);
+ mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
@@ -1586,8 +1574,18 @@
});
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
- mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
- && mPanelController != null);
+
+ boolean panelEnabled = initializePanel();
+ if (!panelEnabled) {
+ mBackgroundDrawable = new GradientDrawable(mContext);
+ mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
+ } else {
+ mBackgroundDrawable = mContext.getDrawable(
+ com.android.systemui.R.drawable.global_action_panel_scrim);
+ mScrimAlpha = 1f;
+ }
+ mGlobalActionsLayout.setSnapToEdge(panelEnabled);
+ getWindow().setBackgroundDrawable(mBackgroundDrawable);
}
private int getGlobalActionsLayoutId(Context context) {
@@ -1743,7 +1741,8 @@
*/
private static boolean isPanelEnabled(Context context) {
return FeatureFlagUtils.isEnabled(
- context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); }
+ context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+ }
/**
* Determines whether the Global Actions menu should use a separated view for emergency actions.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 295abcb..2f99cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -596,7 +596,8 @@
@Override
public void appTransitionCancelled(int displayId) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */)
+ .sendToTarget();
}
}
@@ -624,7 +625,8 @@
@Override
public void appTransitionFinished(int displayId) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */)
+ .sendToTarget();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 0a39549..2da6824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -492,13 +492,10 @@
int currentAlpha = getImageAlpha();
ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
mAlphaAnimator = animator;
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- int alpha = (int) animation.getAnimatedValue();
- if (background != null) background.mutate().setAlpha(alpha);
- setImageAlpha(alpha);
- }
+ animator.addUpdateListener(animation -> {
+ int alpha1 = (int) animation.getAnimatedValue();
+ if (background != null) background.mutate().setAlpha(alpha1);
+ setImageAlpha(alpha1);
});
animator.addListener(mAlphaEndListener);
if (interpolator == null) {
@@ -520,6 +517,10 @@
}
}
+ public boolean isAnimatingAlpha() {
+ return mAlphaAnimator != null;
+ }
+
private Animator.AnimatorListener getEndListener(final Runnable runnable) {
return new AnimatorListenerAdapter() {
boolean mCancelled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 14dc272..2bb6e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -32,6 +32,7 @@
import android.view.View;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -58,7 +59,8 @@
private final DisplayManager mDisplayManager;
/** A displayId - nav bar maps. */
- private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+ @VisibleForTesting
+ SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
@Inject
public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
@@ -101,7 +103,8 @@
*
* @param display the display to add navigation bar on.
*/
- private void createNavigationBar(Display display) {
+ @VisibleForTesting
+ void createNavigationBar(Display display) {
if (display == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index 2bbc53c..fdf8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -28,6 +28,7 @@
import android.view.MotionEvent;
import android.view.View;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.statusbar.CommandQueue;
@@ -48,8 +49,10 @@
private StatusBar mStatusBar;
private NavigationBarFragment mNavigationBar;
- private int mDisplayId;
- private int mSystemUiVisibility;
+ @VisibleForTesting
+ int mDisplayId;
+ @VisibleForTesting
+ int mSystemUiVisibility;
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -123,7 +126,8 @@
}
}
- private void notifySystemUiVisibilityChanged(int vis) {
+ @VisibleForTesting
+ void notifySystemUiVisibilityChanged(int vis) {
try {
if (mLastDispatchedSystemUiVisibility != vis) {
mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
@@ -213,11 +217,12 @@
return mask;
}
- private boolean hasNavigationBar() {
+ boolean hasNavigationBar() {
return mNavigationBar != null;
}
- private boolean hasStatusBar() {
+ @VisibleForTesting
+ boolean hasStatusBar() {
return mStatusBar != null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 6fe23fb..847f3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -831,6 +831,15 @@
}
}
+ /**
+ * Sets the alpha of the indication areas and affordances, excluding the lock icon.
+ */
+ public void setAffordanceAlpha(float alpha) {
+ mLeftAffordanceView.setAlpha(alpha);
+ mRightAffordanceView.setAlpha(alpha);
+ mIndicationArea.setAlpha(alpha);
+ }
+
private class DefaultLeftButton implements IntentButton {
private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 7d13679..19373ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -88,6 +88,7 @@
private int mBouncerPromptReason;
private boolean mIsAnimatingAway;
private boolean mIsScrimmed;
+ private ViewGroup mLockIconContainer;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -171,6 +172,10 @@
return isShowing() && mIsScrimmed;
}
+ public ViewGroup getLockIconContainer() {
+ return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer;
+ }
+
/**
* This method must be called at the end of the bouncer animation when
* the translation is performed manually by the user, otherwise FalsingManager
@@ -401,6 +406,7 @@
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
+ mLockIconContainer = mRoot.findViewById(R.id.lock_icon_container);
mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
@@ -420,6 +426,7 @@
if (mRoot != null && mRoot.getParent() == mContainer) {
mContainer.removeView(mRoot);
mRoot = null;
+ mLockIconContainer = null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0978901..ea30451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -159,7 +159,8 @@
private OverviewProxyService mOverviewProxyService;
- private int mDisplayId;
+ @VisibleForTesting
+ public int mDisplayId;
private boolean mIsOnDefaultDisplay;
public boolean mHomeBlockedThisTouch;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index babee53..253bdfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -192,7 +192,6 @@
protected int mQsMinExpansionHeight;
protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
- private int mBouncerTop;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
private float mLastOverscroll;
@@ -325,6 +324,7 @@
private final ShadeController mShadeController =
Dependency.get(ShadeController.class);
private int mDisplayId;
+ private KeyguardBouncer mBouncer;
/**
* Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
@@ -690,11 +690,6 @@
return count;
}
- public void setBouncerTop(int bouncerTop) {
- mBouncerTop = bouncerTop;
- positionClockAndNotifications();
- }
-
private void updateClock() {
if (!mKeyguardStatusViewAnimating) {
mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
@@ -1741,7 +1736,6 @@
}
updateExpandedHeight(expandedHeight);
updateHeader();
- updateUnlockIcon();
updateNotificationTranslucency();
updatePanelExpanded();
if (DEBUG) {
@@ -1834,19 +1828,6 @@
return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
}
- private void updateUnlockIcon() {
- if (mBarState == StatusBarState.KEYGUARD
- || mBarState == StatusBarState.SHADE_LOCKED) {
- boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
- KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
- if (active != mUnlockIconActive && mTracking) {
- lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true, 150,
- Interpolators.FAST_OUT_LINEAR_IN, null);
- }
- mUnlockIconActive = active;
- }
- }
-
/**
* Hides the header when notifications are colliding with it.
*/
@@ -1913,7 +1894,7 @@
? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
0f, 1f, getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
- mKeyguardBottomArea.setAlpha(alpha);
+ mKeyguardBottomArea.setAffordanceAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO);
@@ -2061,11 +2042,6 @@
mAffordanceHelper.reset(true);
}
}
- if (!expand && (mBarState == StatusBarState.KEYGUARD
- || mBarState == StatusBarState.SHADE_LOCKED)) {
- KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
- lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
- }
}
@Override
@@ -2215,22 +2191,6 @@
return;
}
super.startUnlockHintAnimation();
- startHighlightIconAnimation(getCenterIcon());
- }
-
- /**
- * Starts the highlight (making it fully opaque) animation on an icon.
- */
- private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
- icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
- @Override
- public void run() {
- icon.setImageAlpha(icon.getRestingAlpha(),
- true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- Interpolators.FAST_OUT_SLOW_IN, null);
- }
- });
}
@Override
@@ -2969,6 +2929,7 @@
public void onBouncerPreHideAnimation() {
setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
false /* goingToFullShade */);
+ updateLockIcon();
}
@Override
@@ -3058,4 +3019,54 @@
public void showTransientIndication(int id) {
mKeyguardBottomArea.showTransientIndication(id);
}
+
+ /**
+ * Sets the reference to the {@link KeyguardBouncer}.
+ */
+ public void setBouncer(KeyguardBouncer bouncer) {
+ mBouncer = bouncer;
+ updateLockIcon();
+ }
+
+ public void updateLockIcon() {
+ if (mBouncer == null) {
+ return;
+ }
+
+ ViewGroup bouncerContainer = mBouncer.getLockIconContainer();
+ LockIcon lockIcon = mKeyguardBottomArea.getLockIcon();
+
+ if (mBouncer.isAnimatingAway()) {
+ if (!lockIcon.isAnimatingAlpha() && lockIcon.getAlpha() != 0) {
+ lockIcon.setImageAlpha(0, true /* animate */);
+ }
+ // Let's not re-apply the translation if the bouncer is animating, its
+ // animation also includes translation and transition would be jarring.
+ return;
+ }
+
+ float translation = 0;
+ if (bouncerContainer != null) {
+ float bottomAreaContainerY = getCommonTop(lockIcon);
+ float bouncerLockY = getCommonTop(bouncerContainer);
+ if (bouncerLockY < bottomAreaContainerY) {
+ translation = bouncerLockY - bottomAreaContainerY;
+ }
+ }
+ lockIcon.setTranslationY(translation);
+
+ if (lockIcon.getAlpha() != 1) {
+ lockIcon.setImageAlpha(1, false /* animate */);
+ }
+ }
+
+ private static float getCommonTop(View view) {
+ float y = view.getTop();
+ ViewGroup parent = (ViewGroup) view.getParent();
+ while (!(parent instanceof StatusBarWindowView)) {
+ y += parent.getY();
+ parent = (ViewGroup) parent.getParent();
+ }
+ return y;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2495d22..99345d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1115,6 +1115,7 @@
View[] viewsToAnimate = {
mKeyguardBottomArea.getIndicationArea(),
+ mKeyguardBottomArea.getLockIcon(),
mStatusBar.getAmbientIndicationContainer()};
for (View v : viewsToAnimate) {
if (v == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8db0822..7e330e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -882,7 +882,6 @@
mNotificationPanel.getLockIcon());
mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
-
mAmbientIndicationContainer = mStatusBarWindow.findViewById(
R.id.ambient_indication_container);
@@ -1220,6 +1219,7 @@
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
+ mNotificationPanel.setBouncer(mStatusBarKeyguardViewManager.getBouncer());
Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5014783..e8a5c7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -166,16 +166,10 @@
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
mExpansionCallback);
- mContainer.addOnLayoutChangeListener(this::onContainerLayout);
mNotificationPanelView = notificationPanelView;
notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
}
- private void onContainerLayout(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- mNotificationPanelView.setBouncerTop(mBouncer.getTop());
- }
-
@VisibleForTesting
void onPanelExpansionChanged(float expansion, boolean tracking) {
// We don't want to translate the bounce when:
@@ -198,6 +192,7 @@
mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
}
}
+ mNotificationPanelView.updateLockIcon();
}
/**
@@ -795,6 +790,10 @@
setDozing(isDozing);
}
+ public KeyguardBouncer getBouncer() {
+ return mBouncer;
+ }
+
private static class DismissWithActionRequest {
final OnDismissAction dismissAction;
final Runnable cancelAction;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index dd26368..c2f55e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -41,6 +41,7 @@
private CommandQueue mCommandQueue;
private Callbacks mCallbacks;
+ private static final int SECONDARY_DISPLAY = 1;
@Before
public void setup() {
@@ -68,7 +69,6 @@
verify(mCallbacks).removeIcon(eq(slot));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testDisable() {
int state1 = 14;
@@ -79,6 +79,15 @@
}
@Test
+ public void testDisableForSecondaryDisplay() {
+ int state1 = 14;
+ int state2 = 42;
+ mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2);
+ waitForIdleSync();
+ verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true));
+ }
+
+ @Test
public void testExpandNotifications() {
mCommandQueue.animateExpandNotificationsPanel();
waitForIdleSync();
@@ -100,7 +109,6 @@
verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testSetSystemUiVisibility() {
Rect r = new Rect();
@@ -110,7 +118,15 @@
eq(null), eq(r));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testSetSystemUiVisibilityForSecondaryDisplay() {
+ Rect r = new Rect();
+ mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r);
+ waitForIdleSync();
+ verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+ eq(null), eq(r));
+ }
+
@Test
public void testTopAppWindowChanged() {
mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
@@ -118,7 +134,13 @@
verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testTopAppWindowChangedForSecondaryDisplay() {
+ mCommandQueue.topAppWindowChanged(SECONDARY_DISPLAY, true);
+ waitForIdleSync();
+ verify(mCallbacks).topAppWindowChanged(eq(SECONDARY_DISPLAY), eq(true));
+ }
+
@Test
public void testShowImeButton() {
mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
@@ -128,6 +150,14 @@
}
@Test
+ public void testShowImeButtonForSecondaryDisplay() {
+ mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
+ waitForIdleSync();
+ verify(mCallbacks).setImeWindowStatus(
+ eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
+ }
+
+ @Test
public void testShowRecentApps() {
mCommandQueue.showRecentApps(true);
waitForIdleSync();
@@ -176,7 +206,6 @@
verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testSetWindowState() {
mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
@@ -185,13 +214,19 @@
}
@Test
+ public void testSetWindowStateForSecondaryDisplay() {
+ mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2));
+ }
+
+ @Test
public void testScreenPinRequest() {
mCommandQueue.showScreenPinningRequest(1);
waitForIdleSync();
verify(mCallbacks).showScreenPinningRequest(eq(1));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionPending() {
mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
@@ -199,7 +234,13 @@
verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionPendingForSecondaryDisplay() {
+ mCommandQueue.appTransitionPending(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false));
+ }
+
@Test
public void testAppTransitionCancelled() {
mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
@@ -207,7 +248,13 @@
verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionCancelledForSecondaryDisplay() {
+ mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY));
+ }
+
@Test
public void testAppTransitionStarting() {
mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
@@ -216,7 +263,14 @@
eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionStartingForSecondaryDisplay() {
+ mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionStarting(
+ eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false));
+ }
+
@Test
public void testAppTransitionFinished() {
mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
@@ -225,6 +279,13 @@
}
@Test
+ public void testAppTransitionFinishedForSecondaryDisplay() {
+ mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY));
+ }
+
+ @Test
public void testAssistDisclosure() {
mCommandQueue.showAssistDisclosure();
waitForIdleSync();
@@ -290,4 +351,25 @@
waitForIdleSync();
verify(mCallbacks).handleSystemKey(eq(1));
}
+
+ @Test
+ public void testOnDisplayReady() {
+ mCommandQueue.onDisplayReady(DEFAULT_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY));
+ }
+
+ @Test
+ public void testOnDisplayReadyForSecondaryDisplay() {
+ mCommandQueue.onDisplayReady(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY));
+ }
+
+ @Test
+ public void testOnDisplayRemoved() {
+ mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
new file mode 100644
index 0000000..34a726d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2019 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.statusbar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarControllerTest extends SysuiTestCase {
+
+ private NavigationBarController mNavigationBarController;
+ private Display mDisplay;
+ private NavigationBarFragment mDefaultNavBar;
+ private NavigationBarFragment mSecondaryNavBar;
+
+ private static final int SECONDARY_DISPLAY = 1;
+
+ @Before
+ public void setUp() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ mNavigationBarController = spy(
+ new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+ initializeNavigationBars();
+ }
+
+ private void initializeNavigationBars() {
+ mNavigationBarController.mNavigationBars = mock(SparseArray.class);
+ mDefaultNavBar = mock(NavigationBarFragment.class);
+ mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY;
+ doReturn(mDefaultNavBar)
+ .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY);
+
+ mSecondaryNavBar = mock(NavigationBarFragment.class);
+ mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY;
+ doReturn(mSecondaryNavBar)
+ .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY);
+ }
+
+ @After
+ public void tearDown() {
+ mNavigationBarController = null;
+ mDisplay = null;
+ mDefaultNavBar = null;
+ mSecondaryNavBar = null;
+ }
+
+ @Test
+ public void testCreateNavigationBarsIncludeDefaultTrue() {
+ initializeDisplayManager();
+ doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+ mNavigationBarController.createNavigationBars(true);
+
+ verify(mNavigationBarController).createNavigationBar(any(Display.class));
+ }
+
+ @Test
+ public void testCreateNavigationBarsIncludeDefaultFalse() {
+ initializeDisplayManager();
+ doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+ mNavigationBarController.createNavigationBars(false);
+
+ verify(mNavigationBarController, never()).createNavigationBar(any());
+ }
+
+ private void initializeDisplayManager() {
+ DisplayManager displayManager = mock(DisplayManager.class);
+ mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
+ Display[] displays = {mDisplay};
+ when(displayManager.getDisplays()).thenReturn(displays);
+ mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager);
+ }
+
+ // Tests if NPE occurs when call checkNavBarModes() with invalid display.
+ @Test
+ public void testCheckNavBarModesWithInvalidDisplay() {
+ mNavigationBarController.checkNavBarModes(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testCheckNavBarModesWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).checkNavBarModes();
+
+ mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).checkNavBarModes();
+ }
+
+ @Test
+ public void testCheckNavBarModesWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).checkNavBarModes();
+
+ mNavigationBarController.checkNavBarModes(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).checkNavBarModes();
+ }
+
+ // Tests if NPE occurs when call finishBarAnimations() with invalid display.
+ @Test
+ public void testFinishBarAnimationsWithInvalidDisplay() {
+ mNavigationBarController.finishBarAnimations(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testFinishBarAnimationsWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).finishBarAnimations();
+
+ mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).finishBarAnimations();
+ }
+
+ @Test
+ public void testFinishBarAnimationsWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).finishBarAnimations();
+
+ mNavigationBarController.finishBarAnimations(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).finishBarAnimations();
+ }
+
+ // Tests if NPE occurs when call touchAutoDim() with invalid display.
+ @Test
+ public void testTouchAutoDimWithInvalidDisplay() {
+ mNavigationBarController.touchAutoDim(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testTouchAutoDimWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).touchAutoDim();
+
+ mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).touchAutoDim();
+ }
+
+ @Test
+ public void testTouchAutoDimWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).touchAutoDim();
+
+ mNavigationBarController.touchAutoDim(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).touchAutoDim();
+ }
+
+ // Tests if NPE occurs when call transitionTo() with invalid display.
+ @Test
+ public void testTransitionToWithInvalidDisplay() {
+ mNavigationBarController.transitionTo(INVALID_DISPLAY, 3, true);
+ }
+
+ @Test
+ public void testTransitionToWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).transitionTo(anyInt(), anyBoolean());
+
+ mNavigationBarController.transitionTo(DEFAULT_DISPLAY, 3, true);
+
+ verify(mDefaultNavBar).transitionTo(eq(3), eq(true));
+ }
+
+ @Test
+ public void testTransitionToWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).transitionTo(anyInt(), anyBoolean());
+
+ mNavigationBarController.transitionTo(SECONDARY_DISPLAY, 3, true);
+
+ verify(mSecondaryNavBar).transitionTo(eq(3), eq(true));
+ }
+
+ // Tests if NPE occurs when call disableAnimationsDuringHide() with invalid display.
+ @Test
+ public void testDisableAnimationsDuringHideWithInvalidDisplay() {
+ mNavigationBarController.disableAnimationsDuringHide(INVALID_DISPLAY, 500L);
+ }
+
+ @Test
+ public void testDisableAnimationsDuringHideWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).disableAnimationsDuringHide(anyLong());
+
+ mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, 500L);
+
+ verify(mDefaultNavBar).disableAnimationsDuringHide(eq(500L));
+ }
+
+ @Test
+ public void testDisableAnimationsDuringHideWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).disableAnimationsDuringHide(anyLong());
+
+ mNavigationBarController.disableAnimationsDuringHide(SECONDARY_DISPLAY, 500L);
+
+ verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
new file mode 100644
index 0000000..1b34a75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 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.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest AutoHideControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class AutoHideControllerTest extends SysuiTestCase {
+
+ private AutoHideController mAutoHideController;
+
+ private static final int FULL_MASK = 0xffffffff;
+
+ @Before
+ public void setUp() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ mAutoHideController =
+ spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+ mAutoHideController.mDisplayId = DEFAULT_DISPLAY;
+ mAutoHideController.mSystemUiVisibility = View.VISIBLE;
+ }
+
+ @After
+ public void tearDown() {
+ mAutoHideController = null;
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() {
+ mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect());
+
+ verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() {
+ mAutoHideController
+ .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect());
+
+ verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+ }
+
+ // Test if status bar unhide status doesn't change without status bar.
+ @Test
+ public void testSetSystemUiVisibilityWithoutStatusBar() {
+ doReturn(false).when(mAutoHideController).hasStatusBar();
+ int expectedStatus = View.STATUS_BAR_UNHIDE;
+ mAutoHideController.mSystemUiVisibility =
+ View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE;
+
+ mAutoHideController.setSystemUiVisibility(
+ DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect());
+
+ assertEquals("System UI visibility should not be changed",
+ expectedStatus, mAutoHideController.mSystemUiVisibility);
+ verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus));
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityWithVisChanged() {
+ doReturn(true).when(mAutoHideController).hasStatusBar();
+ doReturn(true).when(mAutoHideController).hasNavigationBar();
+ mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.STATUS_BAR_UNHIDE
+ | View.NAVIGATION_BAR_UNHIDE;
+
+ mAutoHideController.setSystemUiVisibility(
+ DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE,
+ 2, 3, FULL_MASK, null, new Rect());
+
+ int expectedStatus = View.VISIBLE;
+ assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility);
+ verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus));
+ }
+}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 0d17f22..1bcc888 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1880,6 +1880,33 @@
PROBE_STATUS_FAILURE = 3;
}
+ // Codes for cellular data network type
+ enum CellularDataNetworkType {
+ // Unknown network
+ NETWORK_TYPE_UNKNOWN = 0;
+
+ // GSM network
+ NETWORK_TYPE_GSM = 1;
+
+ // CDMA network
+ NETWORK_TYPE_CDMA = 2;
+
+ // CDMA EVDO network
+ NETWORK_TYPE_EVDO_0 = 3;
+
+ // WCDMA network
+ NETWORK_TYPE_UMTS = 4;
+
+ // TDSCDMA network
+ NETWORK_TYPE_TD_SCDMA = 5;
+
+ // LTE network
+ NETWORK_TYPE_LTE = 6;
+
+ // NR network
+ NETWORK_TYPE_NR = 7;
+ }
+
// Absolute milliseconds from device boot when these stats were sampled
optional int64 time_stamp_ms = 1;
@@ -1971,6 +1998,20 @@
// Whether current entry is for the same BSSID on the same frequency compared
// to last entry
optional bool is_same_bssid_and_freq = 29;
+
+ // Cellular data network type currently in use on the device for data transmission
+ optional CellularDataNetworkType cellular_data_network_type = 30;
+
+ // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+ // CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+ optional int32 cellular_signal_strength_dbm = 31;
+
+ // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+ // CDMA: Ecio, EVDO: SNR, GSM: invalid */
+ optional int32 cellular_signal_strength_db = 32;
+
+ // Whether the primary registered cell of current entry is same as that of previous entry
+ optional bool is_same_registered_cell = 33;
}
message WifiUsabilityStats {
diff --git a/services/Android.bp b/services/Android.bp
index 31385ed..567efac 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -26,7 +26,6 @@
"services.contentsuggestions",
"services.coverage",
"services.devicepolicy",
- "services.ipmemorystore",
"services.midi",
"services.net",
"services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 65e31f3..1e3f20e 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -809,13 +809,9 @@
// Announce the end of the gesture recognition.
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+ // Don't announce the end of a the touch interaction if users didn't lift their fingers.
if (interactionEnd) {
- // Announce the end of a the touch interaction.
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- } else {
- // If gesture detection is end, but user doesn't release the finger, announce the
- // transition to exploration state.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
}
mExitGestureDetectionModeDelayed.cancel();
@@ -1151,10 +1147,7 @@
public void run() {
// Announce the end of gesture recognition.
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
- // Clearing puts is in touch exploration state with a finger already
- // down, so announce the transition to exploration state.
clear();
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5582ad7..d3298b9 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -62,6 +62,7 @@
import android.net.RouteInfo;
import android.net.TetherStatsParcel;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.util.NetdService;
import android.os.BatteryStats;
import android.os.Binder;
@@ -80,6 +81,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.telephony.DataConnectionRealTimeInfo;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -1028,6 +1030,46 @@
}
}
+ /**
+ * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
+ */
+ private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg,
+ String iface) {
+ InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
+ cfgParcel.ifName = iface;
+ String hwAddr = cfg.getHardwareAddress();
+ if (!TextUtils.isEmpty(hwAddr)) {
+ cfgParcel.hwAddr = hwAddr;
+ } else {
+ cfgParcel.hwAddr = "";
+ }
+ cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress();
+ cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength();
+ ArrayList<String> flags = new ArrayList<>();
+ for (String flag : cfg.getFlags()) {
+ flags.add(flag);
+ }
+ cfgParcel.flags = flags.toArray(new String[0]);
+
+ return cfgParcel;
+ }
+
+ /**
+ * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
+ */
+ public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) {
+ InterfaceConfiguration cfg = new InterfaceConfiguration();
+ cfg.setHardwareAddress(p.hwAddr);
+
+ final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
+ cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
+ for (String flag : p.flags) {
+ cfg.setFlag(flag);
+ }
+
+ return cfg;
+ }
+
@Override
public InterfaceConfiguration getInterfaceConfig(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1039,7 +1081,7 @@
}
try {
- final InterfaceConfiguration cfg = InterfaceConfiguration.fromParcel(result);
+ final InterfaceConfiguration cfg = fromStableParcel(result);
return cfg;
} catch (IllegalArgumentException iae) {
throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
@@ -1054,7 +1096,7 @@
throw new IllegalStateException("Null LinkAddress given");
}
- final InterfaceConfigurationParcel cfgParcel = cfg.toParcel(iface);
+ final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface);
try {
mNetdService.interfaceSetCfg(cfgParcel);
@@ -1718,12 +1760,27 @@
}
}
+ private static UidRangeParcel makeUidRangeParcel(int start, int stop) {
+ UidRangeParcel range = new UidRangeParcel();
+ range.start = start;
+ range.stop = stop;
+ return range;
+ }
+
+ private static UidRangeParcel[] toStableParcels(UidRange[] ranges) {
+ UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
+ for (int i = 0; i < ranges.length; i++) {
+ stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop);
+ }
+ return stableRanges;
+ }
+
@Override
public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
throws ServiceSpecificException {
mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
try {
- mNetdService.networkRejectNonSecureVpn(add, uidRanges);
+ mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
} catch (ServiceSpecificException e) {
Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
+ ": netd command failed", e);
@@ -1892,7 +1949,7 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mNetdService.networkAddUidRanges(netId, ranges);
+ mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1902,7 +1959,7 @@
public void removeVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mNetdService.networkRemoveUidRanges(netId, ranges);
+ mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1940,7 +1997,7 @@
private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
// UID ranges to close sockets on.
- UidRange[] ranges;
+ UidRangeParcel[] ranges;
// UID ranges whose sockets we won't touch.
int[] exemptUids;
@@ -1948,10 +2005,10 @@
if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
if (getFirewallType(chain) == FIREWALL_WHITELIST) {
// Close all sockets on all non-system UIDs...
- ranges = new UidRange[] {
+ ranges = new UidRangeParcel[] {
// TODO: is there a better way of finding all existing users? If so, we could
// specify their ranges here.
- new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+ makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
};
// ... except for the UIDs that have allow rules.
synchronized (mRulesLock) {
@@ -1978,11 +2035,11 @@
// Close sockets for every UID that has a deny rule...
synchronized (mRulesLock) {
final SparseIntArray rules = getUidFirewallRulesLR(chain);
- ranges = new UidRange[rules.size()];
+ ranges = new UidRangeParcel[rules.size()];
for (int i = 0; i < ranges.length; i++) {
if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
int uid = rules.keyAt(i);
- ranges[numUids] = new UidRange(uid, uid);
+ ranges[numUids] = makeUidRangeParcel(uid, uid);
numUids++;
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f416110..19b0bf7 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3741,6 +3741,7 @@
case "com.facebook.katana": // b/123996076
case "jp.naver.line.android": // b/124767356
case "com.mxtech.videoplayer.ad": // b/124531483
+ case "com.whatsapp": // b/124766614
return Zygote.MOUNT_EXTERNAL_LEGACY;
}
}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7da848c..4e0380d 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -59,6 +59,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
@@ -103,6 +104,7 @@
@Override
public void onStart() {
+ publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
publishLocalService(AttentionManagerInternal.class, new LocalService());
}
@@ -329,17 +331,15 @@
return null;
}
- private void dumpInternal(PrintWriter pw) {
- if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println("Attention Manager Service (dumpsys attention)\n");
+ private void dumpInternal(IndentingPrintWriter ipw) {
+ ipw.println("Attention Manager Service (dumpsys attention) state:\n");
ipw.printPair("context", mContext);
- pw.println();
+ ipw.println();
synchronized (mLock) {
int size = mUserStates.size();
ipw.print("Number user states: ");
- pw.println(size);
+ ipw.println(size);
if (size > 0) {
ipw.increaseIndent();
for (int i = 0; i < size; i++) {
@@ -591,4 +591,15 @@
}
}
}
+
+ private final class BinderService extends Binder {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
+ return;
+ }
+
+ dumpInternal(new IndentingPrintWriter(pw, " "));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 69a9e7e..b774647 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -170,8 +170,15 @@
}
}
- /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
+ /**
+ * Turns speakerphone on/off
+ * @param on
+ * @param eventSource for logging purposes
+ * @return true if speakerphone state changed
+ */
+ /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
synchronized (mDeviceStateLock) {
+ final boolean wasOn = isSpeakerphoneOn();
if (on) {
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
@@ -183,6 +190,7 @@
mForcedUseForCommExt = mForcedUseForComm;
setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ return (wasOn != isSpeakerphoneOn());
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 68f76ab..a14a638 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3331,7 +3331,11 @@
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).toString();
- mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+ final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+ if (stateChanged) {
+ mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+ }
}
/** @see AudioManager#isSpeakerphoneOn() */
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 192ad6d..7b691b4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -28,6 +28,7 @@
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.ControllerCallbackLink;
+import android.media.session.ISession;
import android.media.session.ISessionController;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
@@ -35,7 +36,6 @@
import android.media.session.MediaSession.QueueItem;
import android.media.session.PlaybackState;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -45,6 +45,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.util.Log;
@@ -81,7 +82,7 @@
private final Bundle mSessionInfo;
private final ControllerStub mController;
private final MediaSession.Token mSessionToken;
- private final SessionLink mSession;
+ private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService.ServiceImpl mService;
private final Context mContext;
@@ -133,7 +134,7 @@
mSessionInfo = sessionInfo;
mController = new ControllerStub();
mSessionToken = new MediaSession.Token(mController);
- mSession = new SessionLink(new SessionStub());
+ mSession = new SessionStub();
mSessionCb = new SessionCb(cb);
mService = service;
mContext = mService.getContext();
@@ -144,11 +145,11 @@
}
/**
- * Get the session link for the {@link MediaSession}.
+ * Get the session binder for the {@link MediaSession}.
*
- * @return The session link apps talk to.
+ * @return The session binder apps talk to.
*/
- public SessionLink getSessionBinder() {
+ public ISession getSessionBinder() {
return mSession;
}
@@ -818,9 +819,9 @@
}
};
- private final class SessionStub extends SessionLink.SessionStub {
+ private final class SessionStub extends ISession.Stub {
@Override
- public void destroySession() {
+ public void destroySession() throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
mService.destroySession(MediaSessionRecord.this);
@@ -830,18 +831,18 @@
}
@Override
- public void sendEvent(String event, Bundle data) {
+ public void sendEvent(String event, Bundle data) throws RemoteException {
mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
data == null ? null : new Bundle(data));
}
@Override
- public ISessionController getController() {
+ public ISessionController getController() throws RemoteException {
return mController;
}
@Override
- public void setActive(boolean active) {
+ public void setActive(boolean active) throws RemoteException {
mIsActive = active;
final long token = Binder.clearCallingIdentity();
try {
@@ -853,7 +854,7 @@
}
@Override
- public void setFlags(int flags) {
+ public void setFlags(int flags) throws RemoteException {
if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
@@ -872,7 +873,7 @@
}
@Override
- public void setMediaButtonReceiver(PendingIntent pi) {
+ public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
mMediaButtonReceiver = pi;
final long token = Binder.clearCallingIdentity();
try {
@@ -883,12 +884,13 @@
}
@Override
- public void setLaunchPendingIntent(PendingIntent pi) {
+ public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException {
mLaunchIntent = pi;
}
@Override
- public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
+ public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
+ throws RemoteException {
synchronized (mLock) {
MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
.build();
@@ -906,7 +908,7 @@
}
@Override
- public void setPlaybackState(PlaybackState state) {
+ public void setPlaybackState(PlaybackState state) throws RemoteException {
int oldState = mPlaybackState == null
? PlaybackState.STATE_NONE : mPlaybackState.getState();
int newState = state == null
@@ -924,21 +926,21 @@
}
@Override
- public void setQueue(List<QueueItem> queue) {
+ public void setQueue(MediaParceledListSlice queue) throws RemoteException {
synchronized (mLock) {
- mQueue = queue;
+ mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
}
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
}
@Override
- public void setQueueTitle(CharSequence title) {
+ public void setQueueTitle(CharSequence title) throws RemoteException {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
}
@Override
- public void setExtras(Bundle extras) {
+ public void setExtras(Bundle extras) throws RemoteException {
synchronized (mLock) {
mExtras = extras == null ? null : new Bundle(extras);
}
@@ -946,18 +948,18 @@
}
@Override
- public void setRatingType(int type) {
+ public void setRatingType(int type) throws RemoteException {
mRatingType = type;
}
@Override
- public void setCurrentVolume(int volume) {
+ public void setCurrentVolume(int volume) throws RemoteException {
mCurrentVolume = volume;
mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
}
@Override
- public void setPlaybackToLocal(AudioAttributes attributes) {
+ public void setPlaybackToLocal(AudioAttributes attributes) throws RemoteException {
boolean typeChanged;
synchronized (mLock) {
typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
@@ -980,7 +982,7 @@
}
@Override
- public void setPlaybackToRemote(int control, int max) {
+ public void setPlaybackToRemote(int control, int max) throws RemoteException {
boolean typeChanged;
synchronized (mLock) {
typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 94f289f..7c8dc74 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -49,12 +49,12 @@
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
import android.media.session.ISession2TokensListener;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -1001,7 +1001,7 @@
private boolean mVoiceButtonHandled = false;
@Override
- public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
+ public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
Bundle sessionInfo, int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4e8ef71..a679601 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -552,10 +552,21 @@
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
+ * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+ * rollback within that period, the install will proceed without rollback enabled.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK
+ */
+ private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+
+ /**
* The default duration to wait for rollback to be enabled in
* milliseconds.
*/
- private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000;
+ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
/**
* The default response for package verification timeout.
@@ -14754,11 +14765,11 @@
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
- DeviceConfig.Rollback.NAMESPACE,
- DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT,
- DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+ DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
- rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+ rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5810636..e7c9a08 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -104,7 +104,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
@@ -5114,6 +5113,7 @@
awakenDreams();
}
+ // Start dock.
Intent dock = createHomeDockIntent();
if (dock != null) {
try {
@@ -5126,21 +5126,9 @@
}
}
- Intent intent;
-
- if (fromHomeKey) {
- intent = new Intent(mHomeIntent);
- intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
- } else {
- intent = mHomeIntent;
- }
- final Bundle bundle = getLaunchDisplayIdBundle(displayId);
- startActivityAsUser(intent, bundle, UserHandle.CURRENT);
- }
-
- private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
- return (displayId == INVALID_DISPLAY) ? null
- : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+ // Start home.
+ mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
+ displayId, fromHomeKey);
}
/**
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 5adcf35..f0e4625 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -115,9 +115,41 @@
public static final int REASON_SETTING_CHANGED = 8;
public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
- public static final int REASON_STICKY_RESTORE_OFF = 11;
- public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 12;
- public static final int REASON_TIMEOUT = 13;
+ public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11;
+ public static final int REASON_TIMEOUT = 12;
+
+ static String reasonToString(int reason) {
+ switch (reason) {
+ case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON:
+ return "Percentage Auto ON";
+ case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF:
+ return "Percentage Auto OFF";
+ case BatterySaverController.REASON_MANUAL_ON:
+ return "Manual ON";
+ case BatterySaverController.REASON_MANUAL_OFF:
+ return "Manual OFF";
+ case BatterySaverController.REASON_STICKY_RESTORE:
+ return "Sticky restore";
+ case BatterySaverController.REASON_INTERACTIVE_CHANGED:
+ return "Interactivity changed";
+ case BatterySaverController.REASON_POLICY_CHANGED:
+ return "Policy changed";
+ case BatterySaverController.REASON_PLUGGED_IN:
+ return "Plugged in";
+ case BatterySaverController.REASON_SETTING_CHANGED:
+ return "Setting changed";
+ case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON:
+ return "Dynamic Warning Auto ON";
+ case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF:
+ return "Dynamic Warning Auto OFF";
+ case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED:
+ return "Adaptive Power Savings changed";
+ case BatterySaverController.REASON_TIMEOUT:
+ return "timeout";
+ default:
+ return "Unknown reason: " + reason;
+ }
+ }
/**
* Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af5d40bf..8f2e997 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,6 +15,8 @@
*/
package com.android.server.power.batterysaver;
+import static com.android.server.power.batterysaver.BatterySaverController.reasonToString;
+
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -49,6 +51,42 @@
* Do not call out with the lock held. (Settings provider is okay.)
*
* Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
+ *
+ * Current state machine. This can be visualized using Graphviz:
+ <pre>
+
+ digraph {
+ STATE_OFF
+ STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"]
+ STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"]
+ STATE_OFF_AUTOMATIC_SNOOZED [
+ label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user."
+ + " The system should not turn it back on automatically."
+ ]
+ STATE_PENDING_STICKY_ON [
+ label="STATE_PENDING_STICKY_ON\n"
+ + " Turned on manually by the user and then plugged in. Will turn back on after unplug."
+ ]
+
+ STATE_OFF -> STATE_MANUAL_ON [label="manual"]
+ STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"]
+
+ STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"]
+ STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"]
+
+ STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"]
+ STATE_PENDING_STICKY_ON -> STATE_OFF [
+ label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold"
+ ]
+
+ STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"]
+ STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"]
+
+ STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"]
+ STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"]
+
+ </pre>
+ }
*/
public class BatterySaverStateMachine {
private static final String TAG = "BatterySaverStateMachine";
@@ -60,6 +98,25 @@
private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L;
+ /** Turn off adaptive battery saver if the device has charged above this level. */
+ private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80;
+
+ private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF;
+
+ /** Turned on manually by the user. */
+ private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON;
+
+ /** Turned on automatically by the system. */
+ private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON;
+
+ /** Turned off manually by the user. The system should not turn it back on automatically. */
+ private static final int STATE_OFF_AUTOMATIC_SNOOZED =
+ BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED;
+
+ /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */
+ private static final int STATE_PENDING_STICKY_ON =
+ BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON;
+
private final Context mContext;
private final BatterySaverController mBatterySaverController;
@@ -75,6 +132,9 @@
@GuardedBy("mLock")
private boolean mBatteryStatusSet;
+ @GuardedBy("mLock")
+ private int mState;
+
/** Whether the device is connected to any power source. */
@GuardedBy("mLock")
private boolean mIsPowered;
@@ -142,13 +202,6 @@
private boolean mDynamicPowerSavingsBatterySaver;
/**
- * Whether BS has been manually disabled while the battery level is low, in which case we
- * shouldn't auto re-enable it until the battery level is not low.
- */
- @GuardedBy("mLock")
- private boolean mBatterySaverSnoozing;
-
- /**
* Last reason passed to {@link #enableBatterySaverLocked}.
*/
@GuardedBy("mLock")
@@ -181,6 +234,7 @@
mLock = lock;
mContext = context;
mBatterySaverController = batterySaverController;
+ mState = STATE_OFF;
mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
@@ -188,8 +242,36 @@
com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
}
- private boolean isAutoBatterySaverConfiguredLocked() {
- return mSettingBatterySaverTriggerThreshold > 0;
+ /** @return true if the automatic percentage based mode should be used */
+ private boolean isAutomaticModeActiveLocked() {
+ return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+ && mSettingBatterySaverTriggerThreshold > 0;
+ }
+
+ /**
+ * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()}
+ * returns {@code false}.
+ *
+ * @return true if the battery level is below automatic's threshold.
+ */
+ private boolean isInAutomaticLowZoneLocked() {
+ return mIsBatteryLevelLow;
+ }
+
+ /** @return true if the dynamic mode should be used */
+ private boolean isDynamicModeActiveLocked() {
+ return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+ && mDynamicPowerSavingsBatterySaver;
+ }
+
+ /**
+ * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()}
+ * returns {@code false}.
+ *
+ * @return true if the battery level is below dynamic's threshold.
+ */
+ private boolean isInDynamicLowZoneLocked() {
+ return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
}
/**
@@ -233,7 +315,14 @@
Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
+
synchronized (mLock) {
+ final boolean lowPowerModeEnabledSticky = getGlobalSetting(
+ Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
+
+ if (lowPowerModeEnabledSticky) {
+ mState = STATE_PENDING_STICKY_ON;
+ }
mBootCompleted = true;
@@ -362,6 +451,8 @@
? "Global.low_power changed to 1" : "Global.low_power changed to 0";
enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
BatterySaverController.REASON_SETTING_CHANGED, reason);
+ } else {
+ doAutoBatterySaverLocked();
}
}
@@ -428,17 +519,6 @@
}
}
- @GuardedBy("mLock")
- private boolean isBatteryLowLocked() {
- final boolean percentageLow =
- mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
- && mIsBatteryLevelLow;
- final boolean dynamicPowerSavingsLow =
- mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
- && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
- return percentageLow || dynamicPowerSavingsLow;
- }
-
/**
* Decide whether to auto-start / stop battery saver.
*/
@@ -449,7 +529,6 @@
+ " mSettingsLoaded=" + mSettingsLoaded
+ " mBatteryStatusSet=" + mBatteryStatusSet
+ " mIsBatteryLevelLow=" + mIsBatteryLevelLow
- + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
+ " mIsPowered=" + mIsPowered
+ " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
+ " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
@@ -460,66 +539,166 @@
return; // Not fully initialized yet.
}
- if (!isBatteryLowLocked()) {
- updateSnoozingLocked(false, "Battery not low");
- }
+ updateStateLocked(false, false);
+ // Adaptive control.
if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed
> ADAPTIVE_CHANGE_TIMEOUT_MS) {
mBatterySaverController.setAdaptivePolicyEnabledLocked(
false, BatterySaverController.REASON_TIMEOUT);
mBatterySaverController.resetAdaptivePolicyLocked(
BatterySaverController.REASON_TIMEOUT);
+ } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) {
+ mBatterySaverController.setAdaptivePolicyEnabledLocked(false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ }
+ }
+
+ /**
+ * Update the state machine based on the current settings and battery/charge status.
+ *
+ * @param manual Whether the change was made by the user.
+ * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param
+ * manual} is true.
+ */
+ @GuardedBy("mLock")
+ private void updateStateLocked(boolean manual, boolean enable) {
+ if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
+ return; // Not fully initialized yet.
}
- if (mIsPowered) {
- updateSnoozingLocked(false, "Plugged in");
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_PLUGGED_IN,
- "Plugged in");
-
- if (mBatteryLevel >= 80 /* Arbitrary level */) {
- mBatterySaverController.setAdaptivePolicyEnabledLocked(
- false, BatterySaverController.REASON_PLUGGED_IN);
+ switch (mState) {
+ case STATE_OFF: {
+ if (!mIsPowered) {
+ if (manual) {
+ if (!enable) {
+ Slog.e(TAG, "Tried to disable BS when it's already OFF");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_ON);
+ mState = STATE_MANUAL_ON;
+ } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+ BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON);
+ mState = STATE_AUTOMATIC_ON;
+ } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+ BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON);
+ mState = STATE_AUTOMATIC_ON;
+ }
+ }
+ break;
}
- } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
- if (mSettingBatterySaverStickyAutoDisableEnabled
- && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
- setStickyActive(false);
- } else {
- // Re-enable BS.
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
- BatterySaverController.REASON_STICKY_RESTORE,
- "Sticky restore");
+ case STATE_MANUAL_ON: {
+ if (manual) {
+ if (enable) {
+ Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_OFF);
+ mState = STATE_OFF;
+ } else if (mIsPowered) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ if (mSettingBatterySaverEnabledSticky
+ && !mBatterySaverStickyBehaviourDisabled) {
+ mState = STATE_PENDING_STICKY_ON;
+ } else {
+ mState = STATE_OFF;
+ }
+ }
+ break;
}
- } else if (mSettingAutomaticBatterySaver
- == PowerManager.POWER_SAVER_MODE_PERCENTAGE
- && isAutoBatterySaverConfiguredLocked()) {
- if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
- BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON,
- "Percentage Auto ON");
- } else {
- // Battery not low
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF,
- "Percentage Auto OFF");
+ case STATE_AUTOMATIC_ON: {
+ if (mIsPowered) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ mState = STATE_OFF;
+ } else if (manual) {
+ if (enable) {
+ Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_OFF);
+ // When battery saver is disabled manually (while battery saver is enabled)
+ // when the battery level is low, we "snooze" BS -- i.e. disable auto battery
+ // saver.
+ // We resume auto-BS once the battery level is not low, or the device is
+ // plugged in.
+ mState = STATE_OFF_AUTOMATIC_SNOOZED;
+ } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF);
+ mState = STATE_OFF;
+ } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF);
+ mState = STATE_OFF;
+ } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_SETTING_CHANGED);
+ mState = STATE_OFF;
+ }
+ break;
}
- } else if (mSettingAutomaticBatterySaver
- == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
- if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
- "Dynamic Warning Auto OFF");
- } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
- BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
- "Dynamic Warning Auto ON");
+
+ case STATE_OFF_AUTOMATIC_SNOOZED: {
+ if (manual) {
+ if (!enable) {
+ Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_ON);
+ mState = STATE_MANUAL_ON;
+ } else if (mIsPowered // Plugging in resets snooze.
+ || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked())
+ || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked())
+ || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) {
+ mState = STATE_OFF;
+ }
+ break;
}
+
+ case STATE_PENDING_STICKY_ON: {
+ if (manual) {
+ // This shouldn't be possible. We'll only be in this state when the device is
+ // plugged in, so the user shouldn't be able to manually change state.
+ Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON");
+ return;
+ }
+ final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
+ && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
+ final boolean isStickyDisabled =
+ mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
+ if (isStickyDisabled || shouldTurnOffSticky) {
+ setStickyActive(false);
+ mState = STATE_OFF;
+ } else if (!mIsPowered) {
+ // Re-enable BS.
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_STICKY_RESTORE);
+ mState = STATE_MANUAL_ON;
+ }
+ break;
+ }
+
+ default:
+ Slog.wtf(TAG, "Unknown state: " + mState);
+ break;
}
- // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
+ }
+
+ @VisibleForTesting
+ int getState() {
+ synchronized (mLock) {
+ return mState;
+ }
}
/**
@@ -533,13 +712,17 @@
Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
}
synchronized (mLock) {
- enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
- (enabled ? BatterySaverController.REASON_MANUAL_ON
- : BatterySaverController.REASON_MANUAL_OFF),
- (enabled ? "Manual ON" : "Manual OFF"));
+ updateStateLocked(true, enabled);
+ // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and
+ // enabled is false
}
}
+ @GuardedBy("mLock")
+ private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
+ enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
+ }
+
/**
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
@@ -566,20 +749,6 @@
mLastChangedIntReason = intReason;
mLastChangedStrReason = strReason;
- if (manual) {
- if (enable) {
- updateSnoozingLocked(false, "Manual snooze OFF");
- } else {
- // When battery saver is disabled manually (while battery saver is enabled)
- // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
- // We resume auto-BS once the battery level is not low, or the device is plugged in.
- if (mBatterySaverController.isFullEnabled() && isBatteryLowLocked()) {
- updateSnoozingLocked(true, "Manual snooze");
- }
- // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true
- }
- }
-
mSettingBatterySaverEnabled = enable;
putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
@@ -641,15 +810,6 @@
manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
}
- @GuardedBy("mLock")
- private void updateSnoozingLocked(boolean snoozing, String reason) {
- if (mBatterySaverSnoozing == snoozing) {
- return;
- }
- if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop") + " reason=" + reason);
- mBatterySaverSnoozing = snoozing;
- }
-
private void setStickyActive(boolean active) {
mSettingBatterySaverEnabledSticky = active;
putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
@@ -684,6 +844,8 @@
pw.print(")");
}
pw.println();
+ pw.print(" mState=");
+ pw.println(mState);
pw.print(" mLastChangedIntReason=");
pw.println(mLastChangedIntReason);
@@ -697,9 +859,6 @@
pw.print(" mBatteryStatusSet=");
pw.println(mBatteryStatusSet);
- pw.print(" mBatterySaverSnoozing=");
- pw.println(mBatterySaverSnoozing);
-
pw.print(" mIsPowered=");
pw.println(mIsPowered);
pw.print(" mBatteryLevel=");
@@ -731,6 +890,7 @@
proto.write(BatterySaverStateMachineProto.ENABLED,
mBatterySaverController.isEnabled());
+ proto.write(BatterySaverStateMachineProto.STATE, mState);
proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED,
mBatterySaverController.isFullEnabled());
proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED,
@@ -742,8 +902,6 @@
proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
- proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
- mBatterySaverSnoozing);
proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 83d18a6..c3582ea 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -535,8 +535,8 @@
private void updateRollbackLifetimeDurationInMillis() {
mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
- DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS);
if (mRollbackLifetimeDurationInMillis < 0) {
mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2b17d19..1800433 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -19,6 +19,8 @@
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.os.Process.getPidsForCommands;
import static android.os.Process.getUidForPid;
+import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
+import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
@@ -89,6 +91,7 @@
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -1968,7 +1971,7 @@
pulledData.add(e);
}
- private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+ private void pullExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
StorageManager storageManager = mContext.getSystemService(StorageManager.class);
if (storageManager != null) {
@@ -1976,11 +1979,29 @@
for (VolumeInfo vol : volumes) {
final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
final DiskInfo diskInfo = vol.getDisk();
- if (diskInfo != null && diskInfo.isSd()) {
+ if (diskInfo != null) {
if (envState.equals(Environment.MEDIA_MOUNTED)) {
+ // Get the type of the volume, if it is adoptable or portable.
+ int volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__OTHER;
+ if (vol.getType() == TYPE_PUBLIC) {
+ volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PUBLIC;
+ } else if (vol.getType() == TYPE_PRIVATE) {
+ volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PRIVATE;
+ }
+ // Get the type of external storage inserted in the device (sd cards,
+ // usb, etc)
+ int externalStorageType;
+ if (diskInfo.isSd()) {
+ externalStorageType = StorageEnums.SD_CARD;
+ } else if (diskInfo.isUsb()) {
+ externalStorageType = StorageEnums.USB;
+ } else {
+ externalStorageType = StorageEnums.OTHER;
+ }
StatsLogEventWrapper e =
new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(vol.getType() + 1);
+ e.writeInt(externalStorageType);
+ e.writeInt(volumeType);
e.writeLong(diskInfo.size);
pulledData.add(e);
}
@@ -2185,8 +2206,8 @@
pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
- case StatsLog.SDCARD_INFO: {
- pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+ case StatsLog.EXTERNAL_STORAGE_INFO: {
+ pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
default:
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5a20959..b262a00 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -352,6 +352,19 @@
/** @return The intent used to launch the home activity. */
public abstract Intent getHomeIntent();
public abstract boolean startHomeActivity(int userId, String reason);
+ /**
+ * This starts home activity on displays that can have system decorations based on displayId -
+ * Default display always use primary home component.
+ * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves
+ * according to the priorities listed below.
+ * - If default home is not set, always use the secondary home defined in the config.
+ * - Use currently selected primary home activity.
+ * - Use the activity in the same package as currently selected primary home activity.
+ * If there are multiple activities matched, use first one.
+ * - Use the secondary home defined in the config.
+ */
+ public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId,
+ boolean fromHomeKey);
/** Start home activities on all displays that support system decorations. */
public abstract boolean startHomeOnAllDisplays(int userId, String reason);
/** @return true if the given process is the factory test process. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a1dbbab..118eb5b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6491,6 +6491,13 @@
}
@Override
+ public boolean startHomeOnDisplay(int userId, String reason, int displayId,
+ boolean fromHomeKey) {
+ return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
+ fromHomeKey);
+ }
+
+ @Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f964b57..24cf7f1 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -114,6 +114,7 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.UserState;
+import com.android.server.policy.WindowManagerPolicy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -345,6 +346,10 @@
}
}
+ boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+ return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/);
+ }
+
/**
* This starts home activity on displays that can have system decorations based on displayId -
* Default display always use primary home component.
@@ -356,7 +361,12 @@
* If there are multiple activities matched, use first one.
* - Use the secondary home defined in the config.
*/
- boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+ boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) {
+ // Fallback to top focused display if the displayId is invalid.
+ if (displayId == INVALID_DISPLAY) {
+ displayId = getTopDisplayFocusedStack().mDisplayId;
+ }
+
Intent homeIntent;
ActivityInfo aInfo;
if (displayId == DEFAULT_DISPLAY) {
@@ -380,6 +390,10 @@
// Updates the home component of the intent.
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+ // Updates the extra information of the intent.
+ if (fromHomeKey) {
+ homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
+ }
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
deleted file mode 100644
index 013cf56..0000000
--- a/services/ipmemorystore/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-java_library_static {
- name: "services.ipmemorystore",
- srcs: ["java/**/*.java"],
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3f323d9..39af565 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
-import com.android.server.net.ipmemorystore.IpMemoryStoreService;
import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.oemlock.OemLockService;
@@ -1264,14 +1263,6 @@
}
traceEnd();
- traceBeginAndSlog("StartIpMemoryStoreService");
- try {
- ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
- new IpMemoryStoreService(context));
- } catch (Throwable e) {
- reportWtf("starting IP Memory Store Service", e);
- }
- traceEnd();
traceBeginAndSlog("StartIpSecService");
try {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 8ad4d76..486d15d 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -7,6 +7,19 @@
]
}
+java_library_static {
+ name: "ipmemorystore-client",
+ sdk_version: "system_current",
+ srcs: [
+ ":framework-annotations",
+ "java/android/net/IpMemoryStoreClient.java",
+ "java/android/net/ipmemorystore/**.java",
+ ],
+ static_libs: [
+ "ipmemorystore-aidl-interfaces-java",
+ ]
+}
+
filegroup {
name: "services-networkstack-shared-srcs",
srcs: [
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..9248299
--- /dev/null
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 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;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Manager class used to communicate with the ip memory store service in the network stack,
+ * which is running in a separate module.
+ * @hide
+*/
+public class IpMemoryStore extends IpMemoryStoreClient {
+ private final CompletableFuture<IIpMemoryStore> mService;
+
+ public IpMemoryStore(@NonNull final Context context) {
+ super(context);
+ mService = new CompletableFuture<>();
+ getNetworkStackClient().fetchIpMemoryStore(
+ new IIpMemoryStoreCallbacks.Stub() {
+ @Override
+ public void onIpMemoryStoreFetched(final IIpMemoryStore memoryStore) {
+ mService.complete(memoryStore);
+ }
+ });
+ }
+
+ @Override
+ protected IIpMemoryStore getService() throws InterruptedException, ExecutionException {
+ return mService.get();
+ }
+
+ @VisibleForTesting
+ protected NetworkStackClient getNetworkStackClient() {
+ return NetworkStackClient.getInstance();
+ }
+
+ /** Gets an instance of the memory store */
+ @NonNull
+ public static IpMemoryStore getMemoryStore(final Context context) {
+ return new IpMemoryStore(context);
+ }
+}
diff --git a/core/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStoreClient.java
similarity index 68%
rename from core/java/android/net/IpMemoryStore.java
rename to services/net/java/android/net/IpMemoryStoreClient.java
index 2f4d9bc..2f4fdbd 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemService;
import android.content.Context;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,23 +26,34 @@
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
import android.os.RemoteException;
+import android.util.Log;
-import com.android.internal.util.Preconditions;
+import java.util.concurrent.ExecutionException;
/**
- * The interface for system components to access the IP memory store.
- * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in a separate module.
* @hide
*/
-@SystemService(Context.IP_MEMORY_STORE_SERVICE)
-public class IpMemoryStore {
- @NonNull final Context mContext;
- @NonNull final IIpMemoryStore mService;
+public abstract class IpMemoryStoreClient {
+ private static final String TAG = IpMemoryStoreClient.class.getSimpleName();
+ private final Context mContext;
- public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+ public IpMemoryStoreClient(@NonNull final Context context) {
+ if (context == null) throw new IllegalArgumentException("missing context");
+ mContext = context;
+ }
+
+ @NonNull
+ protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException;
+
+ protected StatusParcelable internalErrorStatus() {
+ final StatusParcelable error = new StatusParcelable();
+ error.resultCode = Status.ERROR_UNKNOWN;
+ return error;
}
/**
@@ -66,9 +76,13 @@
@NonNull final NetworkAttributes attributes,
@Nullable final IOnStatusListener listener) {
try {
- mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ try {
+ getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onComplete(internalErrorStatus());
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error storing network attributes", e);
}
}
@@ -87,9 +101,13 @@
@NonNull final String name, @NonNull final Blob data,
@Nullable final IOnStatusListener listener) {
try {
- mService.storeBlob(l2Key, clientId, name, data, listener);
+ try {
+ getService().storeBlob(l2Key, clientId, name, data, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onComplete(internalErrorStatus());
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error storing blob", e);
}
}
@@ -110,9 +128,13 @@
public void findL2Key(@NonNull final NetworkAttributes attributes,
@NonNull final IOnL2KeyResponseListener listener) {
try {
- mService.findL2Key(attributes.toParcelable(), listener);
+ try {
+ getService().findL2Key(attributes.toParcelable(), listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onL2KeyResponse(internalErrorStatus(), null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error finding L2 Key", e);
}
}
@@ -128,9 +150,13 @@
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
@NonNull final IOnSameNetworkResponseListener listener) {
try {
- mService.isSameNetwork(l2Key1, l2Key2, listener);
+ try {
+ getService().isSameNetwork(l2Key1, l2Key2, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onSameNetworkResponse(internalErrorStatus(), null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error checking for network sameness", e);
}
}
@@ -146,9 +172,13 @@
public void retrieveNetworkAttributes(@NonNull final String l2Key,
@NonNull final IOnNetworkAttributesRetrieved listener) {
try {
- mService.retrieveNetworkAttributes(l2Key, listener);
+ try {
+ getService().retrieveNetworkAttributes(l2Key, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error retrieving network attributes", e);
}
}
@@ -166,14 +196,13 @@
public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
@NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
try {
- mService.retrieveBlob(l2Key, clientId, name, listener);
+ try {
+ getService().retrieveBlob(l2Key, clientId, name, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onBlobRetrieved(internalErrorStatus(), null, null, null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error retrieving blob", e);
}
}
-
- /** Gets an instance of the memory store */
- public static IpMemoryStore getMemoryStore(final Context context) {
- return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
- }
}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index cc09fe3..7befd087 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -130,6 +130,21 @@
});
}
+ /**
+ * Get an instance of the IpMemoryStore.
+ *
+ * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
+ */
+ public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.fetchIpMemoryStore(cb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
private class NetworkStackConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
similarity index 97%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to services/net/java/android/net/TcpKeepalivePacketData.java
index 99d36c5..398a6b31 100644
--- a/core/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -167,8 +167,9 @@
tcpWndScale);
}
- /* Parcelable Implementation. */
- /* Note that this object implements parcelable (and needs to keep doing this as it inherits
+ /**
+ * Parcelable Implementation.
+ * Note that this object implements parcelable (and needs to keep doing this as it inherits
* from a class that does), but should usually be parceled as a stable parcelable using
* the toStableParcelable() and fromStableParcelable() methods.
*/
@@ -194,7 +195,7 @@
}
/** Parcelable Creator. */
- public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
new Parcelable.Creator<TcpKeepalivePacketData>() {
public TcpKeepalivePacketData createFromParcel(Parcel in) {
return new TcpKeepalivePacketData(in);
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/NetworkAttributes.java
rename to services/net/java/android/net/ipmemorystore/NetworkAttributes.java
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
rename to services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
diff --git a/core/java/android/net/ipmemorystore/Status.java b/services/net/java/android/net/ipmemorystore/Status.java
similarity index 97%
rename from core/java/android/net/ipmemorystore/Status.java
rename to services/net/java/android/net/ipmemorystore/Status.java
index cacd42d..13242c0 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/services/net/java/android/net/ipmemorystore/Status.java
@@ -32,6 +32,7 @@
public static final int ERROR_ILLEGAL_ARGUMENT = -2;
public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3;
public static final int ERROR_STORAGE = -4;
+ public static final int ERROR_UNKNOWN = -5;
public final int resultCode;
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 86e8598..2e5efbd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -28,6 +28,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.os.PowerManager;
import android.provider.Settings.Global;
import androidx.test.filters.SmallTest;
@@ -452,6 +453,21 @@
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
+
+ // Disable auto battery saver.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ mDevice.setBatteryLevel(25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(25, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // PowerManager sets batteryLow to true at 15% if battery saver trigger level is lower.
+ mDevice.setBatteryLevel(15);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(15, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
}
@Test
@@ -542,6 +558,12 @@
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
+ mDevice.setBatteryLevel(97);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+ assertEquals(97, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
mDevice.setBatteryLevel(95);
assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
@@ -719,6 +741,48 @@
}
@Test
+ public void testAutoBatterySaver_withSticky_withAutoOffToggled() {
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+ // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+ // with battery level change above threshold.
+ mDevice.setBatteryLevel(100);
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(95);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Disable auto disable while in the pending sticky state. BS should reactivate after
+ // unplug.
+ mDevice.setPowered(true);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS should activate.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Enable auto disable while in the pending sticky state. Sticky should turn off after
+ // unplug.
+ mDevice.setPowered(true);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+ }
+
+ @Test
public void testAutoBatterySaver_withStickyDisabled() {
when(mMockResources.getBoolean(
com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
@@ -739,7 +803,9 @@
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
+ mDevice.setPowered(true);
mDevice.setBatteryLevel(80);
+ mDevice.setPowered(false);
assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
assertEquals(80, mPersistedState.batteryLevel);
@@ -830,10 +896,9 @@
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
- // Reboot -- setting BS from adb is also sticky.
+ // Reboot -- LOW_POWER_MODE shouldn't be persisted.
initDevice();
-
- assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
}
@@ -841,7 +906,8 @@
@Test
public void testAutoBatterySaver_smartBatterySaverEnabled() {
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
- mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
assertEquals(false, mDevice.batterySaverEnabled);
@@ -922,8 +988,8 @@
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
- // changes are only registered if some battery level changed
- assertEquals(false, mDevice.batterySaverEnabled);
+ // Changes should register immediately.
+ assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(70, mPersistedState.batteryLevel);
mDevice.setBatteryLevel(69);
@@ -935,8 +1001,8 @@
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
- // changes are only registered if battery level changed
- assertEquals(true, mDevice.batterySaverEnabled);
+ // Changes should register immediately.
+ assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(69, mPersistedState.batteryLevel);
mDevice.setBatteryLevel(68);
@@ -956,4 +1022,220 @@
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
}
+
+ @Test
+ public void testAutoBatterySaver_snoozed_autoEnabled() {
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 30);
+ // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's
+ // not enabled.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(51);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(51, mPersistedState.batteryLevel);
+
+ // Hit dynamic threshold. BS should be disabled since dynamic is off
+ mDevice.setBatteryLevel(50);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(50, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(20);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold. Level is still below, so should still be snoozed.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+ // disabled.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10);
+ // "batteryLow" is set in setBatteryLevel.
+ mDevice.setBatteryLevel(19);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(19, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(10);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ // Plug in and out, snooze will reset.
+ mDevice.setPowered(true);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(60);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(60, mPersistedState.batteryLevel);
+
+ // Test toggling resets snooze.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.setPowered(false);
+ mDevice.setBatteryLevel(45);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ // Disable and re-enable.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+ assertEquals(45, mPersistedState.batteryLevel);
+ }
+
+ @Test
+ public void testAutoBatterySaver_snoozed_dynamicEnabled() {
+ // Test auto threshold higher than dynamic to make sure it doesn't interfere when it's
+ // not enabled.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(51);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(51, mPersistedState.batteryLevel);
+
+ // Hit automatic threshold. BS should be disabled since automatic is off
+ mDevice.setBatteryLevel(50);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(50, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(20);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold. Level is still below, so should still be snoozed.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+ // disabled.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 10);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(10);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ // Plug in and out, snooze will reset.
+ mDevice.setPowered(true);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(60);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(60, mPersistedState.batteryLevel);
+
+ // Test toggling resets snooze.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+ mDevice.setPowered(false);
+ mDevice.setBatteryLevel(45);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ // Disable and re-enable.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+ assertEquals(45, mPersistedState.batteryLevel);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9504381..cd095a5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -250,7 +250,7 @@
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setRank(123)
.setPerson(makePerson("person", "personKey", "personUri"))
- .setLongLived()
+ .setLongLived(true)
.setExtras(pb)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -352,7 +352,7 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setPerson(makePerson("person", "personKey", "personUri"))
- .setLongLived()
+ .setLongLived(true)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 5556a15..febb795 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -43,7 +43,6 @@
*/
@SmallTest
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
@Mock
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index b9e9909..d8a01b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -159,7 +159,6 @@
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b03f63b..4f8fe5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -87,7 +87,6 @@
*/
@SmallTest
@Presubmit
-@FlakyTest(bugId = 124127512)
public class WindowStateTests extends WindowTestsBase {
private static int sPreviousNewInsetsMode;
@@ -363,7 +362,6 @@
assertFalse(app.canAffectSystemUiFlags());
}
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testVisibleWithInsetsProvider() throws Exception {
final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index f0a26f5..ca264f7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -318,8 +318,8 @@
public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
/** APN has been disabled. */
public static final int APN_DISABLED = 0x7FD;
- /** PPP inactivity timer expired. */
- public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+ /** Maximum PPP inactivity timer expired. */
+ public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
/** IPv6 address transfer failed. */
public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
/** Target RAT swap failed. */
@@ -339,12 +339,12 @@
* IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
* number of IPv4 data connections.
*/
- public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804;
+ public static final int MAX_IPV4_CONNECTIONS = 0x804;
/**
* IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
* number of IPv6 data connections.
*/
- public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805;
+ public static final int MAX_IPV6_CONNECTIONS = 0x805;
/**
* New PDN bring up is rejected during interface selection because the UE has already allotted
* the available interfaces for other PDNs.
@@ -416,7 +416,7 @@
*/
public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
/** Maximum access probes transmitted. */
- public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F;
+ public static final int MAX_ACCESS_PROBE = 0x81F;
/** Concurrent service is not supported by base station. */
public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
/** There was no response received from the base station. */
@@ -1079,14 +1079,14 @@
SIM_CARD_CHANGED,
LOW_POWER_MODE_OR_POWERING_DOWN,
APN_DISABLED,
- PPP_INACTIVITY_TIMER_EXPIRED,
+ MAX_PPP_INACTIVITY_TIMER_EXPIRED,
IPV6_ADDRESS_TRANSFER_FAILED,
TRAT_SWAP_FAILED,
EHRPD_TO_HRPD_FALLBACK,
MIP_CONFIG_FAILURE,
PDN_INACTIVITY_TIMER_EXPIRED,
- IPV4_CONNECTIONS_LIMIT_REACHED,
- IPV6_CONNECTIONS_LIMIT_REACHED,
+ MAX_IPV4_CONNECTIONS,
+ MAX_IPV6_CONNECTIONS,
APN_MISMATCH,
IP_VERSION_MISMATCH,
DUN_CALL_DISALLOWED,
@@ -1112,7 +1112,7 @@
CDMA_INCOMING_CALL,
CDMA_ALERT_STOP,
CHANNEL_ACQUISITION_FAILURE,
- ACCESS_PROBE_LIMIT_REACHED,
+ MAX_ACCESS_PROBE,
CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
NO_RESPONSE_FROM_BASE_STATION,
REJECTED_BY_BASE_STATION,
@@ -1447,14 +1447,14 @@
sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
- sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED");
+ sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
- sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED");
- sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED");
+ sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
+ sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
@@ -1480,7 +1480,7 @@
sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
- sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED");
+ sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
"CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66ef531..c91f16b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8293,7 +8293,7 @@
* @see SubscriptionManager#getDefaultSubscriptionId()
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isVolteAvailable() {
try {
return getITelephony().isAvailable(getSubId(),
@@ -8312,7 +8312,7 @@
* @return true if VT is available, or false if it is unavailable or unknown.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isVideoTelephonyAvailable() {
try {
return getITelephony().isVideoTelephonyAvailable(getSubId());
@@ -8327,7 +8327,7 @@
* @return true if VoWiFi is available, or false if it is unavailable or unknown.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isWifiCallingAvailable() {
try {
return getITelephony().isWifiCallingAvailable(getSubId());
@@ -9865,8 +9865,11 @@
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
*
+ *
+ * @deprecated
* @hide
*/
+ @Deprecated
@TestApi
public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
String gid2, String plmn, String spn) {
@@ -9874,7 +9877,35 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
telephony.setCarrierTestOverride(
- getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+ getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+ null, null);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ }
+
+ /**
+ * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+ * plmn, spn, apn and carrier priviledge. This would be handy for, eg, forcing a particular
+ * carrier id, carrier's config (also any country or carrier overlays) to be loaded when using
+ * a test SIM with a call box.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+ String gid2, String plmn, String spn,
+ String carrierPriviledgeRules, String apn) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setCarrierTestOverride(
+ getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+ carrierPriviledgeRules, apn);
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index e651783..875bd78 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -285,6 +285,8 @@
* {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and
* {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription.
*
+ * <p>Expected type of the extra data: int
+ *
* @hide
*/
@SystemApi
@@ -295,6 +297,8 @@
* Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean
* value of whether to enable or disable the targeted subscription.
*
+ * <p>Expected type of the extra data: boolean
+ *
* @hide
*/
@SystemApi
@@ -305,6 +309,8 @@
* Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new
* nickname for the targeted subscription.
*
+ * <p>Expected type of the extra data: String
+ *
* @hide
*/
@SystemApi
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62b92fd..c2c31cc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1683,7 +1683,7 @@
* (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
*/
void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
- String gid2, String plmn, String spn);
+ String gid2, String plmn, String spn, String carrierPrivilegeRules, String apn);
/**
* A test API to return installed carrier id list version.
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7505230..48bc9e8 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -346,8 +346,8 @@
Manifest.permission.MANAGE_ROLLBACKS,
Manifest.permission.WRITE_DEVICE_CONFIG);
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(expirationTime), false /* makeDefault*/);
// Pull the new expiration time from DeviceConfig
@@ -382,8 +382,8 @@
assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
} finally {
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -407,8 +407,8 @@
Manifest.permission.WRITE_DEVICE_CONFIG,
Manifest.permission.SET_TIME);
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(expirationTime), false /* makeDefault*/);
// Pull the new expiration time from DeviceConfig
@@ -458,8 +458,8 @@
RollbackTestUtils.forwardTimeBy(-expirationTime);
}
} finally {
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
RollbackTestUtils.dropShellPermissionIdentity();
}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 2539c0f..c62d85e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -13,7 +13,6 @@
"mockito-target-minus-junit4",
"platform-test-annotations",
"services.core",
- "services.ipmemorystore",
"services.net",
],
libs: [
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
index 9ede2b8..975abf4 100644
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ b/tests/net/java/android/net/DnsPacketTest.java
@@ -69,7 +69,7 @@
try {
new TestDnsPacket(null);
fail("Exception not thrown for null byte array");
- } catch (DnsPacket.ParseException e) {
+ } catch (ParseException e) {
}
}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 57ecc8f..18c6768 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+
import android.content.Context;
import androidx.test.filters.SmallTest;
@@ -33,13 +36,25 @@
@Mock
Context mMockContext;
@Mock
+ NetworkStackClient mNetworkStackClient;
+ @Mock
IIpMemoryStore mMockService;
IpMemoryStore mStore;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mStore = new IpMemoryStore(mMockContext, mMockService);
+ doAnswer(invocation -> {
+ ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+ .onIpMemoryStoreFetched(mMockService);
+ return null;
+ }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+ mStore = new IpMemoryStore(mMockContext) {
+ @Override
+ protected NetworkStackClient getNetworkStackClient() {
+ return mNetworkStackClient;
+ }
+ };
}
@Test
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 830c928..9b4f49c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -101,6 +101,7 @@
@After
public void tearDown() throws Exception {
RecurrenceRule.sClock = sOriginalClock;
+ NetworkTemplate.resetForceAllNetworkTypes();
}
private void setClock(Instant instant) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 598448b..bce526d 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,6 +19,7 @@
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -41,6 +42,7 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
@@ -132,6 +134,8 @@
private static final String TEST_IFACE = "test0";
private static final String TEST_IFACE2 = "test1";
+ private static final String TUN_IFACE = "test_nss_tun0";
+
private static final long TEST_START = 1194220800000L;
private static final String IMSI_1 = "310004";
@@ -145,10 +149,12 @@
private static final int UID_RED = 1001;
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
-
+ private static final int UID_VPN = 1004;
private static final Network WIFI_NETWORK = new Network(100);
private static final Network MOBILE_NETWORK = new Network(101);
+ private static final Network VPN_NETWORK = new Network(102);
+
private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
@@ -914,7 +920,113 @@
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
+ }
+ @Test
+ public void vpnWithOneUnderlyingIface() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ expectDefaultSettings();
+ NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
+ // VPN sent/received 1650 bytes (150 packets) over WiFi.
+ // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
+ // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
+ .addValues(
+ TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
+ assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
+ assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
+ }
+
+ @Test
+ public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ expectDefaultSettings();
+ NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
+ // VPN sent/received 1000 bytes (100 packets) over WiFi.
+ // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
+ // with nothing attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L)
+ .addValues(
+ TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0);
+ assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0);
+ assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+ }
+
+ @Test
+ public void vpnWithIncorrectUnderlyingIface() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
+ // but has declared only WiFi (TEST_IFACE) in its underlying network set.
+ expectDefaultSettings();
+ NetworkState[] networkStates =
+ new NetworkState[] {
+ buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
+ };
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // VPN sent/received 1100 bytes (100 packets) over Cell.
+ // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(
+ TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
}
@Test
@@ -1262,6 +1374,22 @@
return new NetworkStats(getElapsedRealtime(), 0);
}
+ private static NetworkState buildVpnState() {
+ final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
+ info.setDetailedState(DetailedState.CONNECTED, null, null);
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(TUN_IFACE);
+ return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+ }
+
+ private static VpnInfo createVpnInfo(String underlyingIface) {
+ VpnInfo info = new VpnInfo();
+ info.ownerUid = UID_VPN;
+ info.vpnIface = TUN_IFACE;
+ info.primaryUnderlyingIface = underlyingIface;
+ return info;
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 51aa93a..01176f2 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -98,6 +99,10 @@
private final int mProbeMcsRateSinceLastUpdate;
/** Rx link speed at the sample time in Mbps */
private final int mRxLinkSpeedMbps;
+ private final @NetworkType int mCellularDataNetworkType;
+ private final int mCellularSignalStrengthDbm;
+ private final int mCellularSignalStrengthDb;
+ private final boolean mIsSameRegisteredCell;
/** Constructor function {@hide} */
public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps,
@@ -109,7 +114,10 @@
long totalHotspot2ScanTimeMillis,
long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx,
@ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis,
- int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) {
+ int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps,
+ @NetworkType int cellularDataNetworkType,
+ int cellularSignalStrengthDbm, int cellularSignalStrengthDb,
+ boolean isSameRegisteredCell) {
mTimeStampMillis = timeStampMillis;
mRssi = rssi;
mLinkSpeedMbps = linkSpeedMbps;
@@ -133,6 +141,10 @@
mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis;
mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
mRxLinkSpeedMbps = rxLinkSpeedMbps;
+ mCellularDataNetworkType = cellularDataNetworkType;
+ mCellularSignalStrengthDbm = cellularSignalStrengthDbm;
+ mCellularSignalStrengthDb = cellularSignalStrengthDb;
+ mIsSameRegisteredCell = isSameRegisteredCell;
}
/** Implement the Parcelable interface */
@@ -165,6 +177,10 @@
dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis);
dest.writeInt(mProbeMcsRateSinceLastUpdate);
dest.writeInt(mRxLinkSpeedMbps);
+ dest.writeInt(mCellularDataNetworkType);
+ dest.writeInt(mCellularSignalStrengthDbm);
+ dest.writeInt(mCellularSignalStrengthDb);
+ dest.writeBoolean(mIsSameRegisteredCell);
}
/** Implement the Parcelable interface */
@@ -179,7 +195,9 @@
in.readLong(), in.readLong(), in.readLong(),
in.readLong(), in.readLong(), in.readLong(),
in.readLong(), in.readLong(), in.readInt(),
- in.readInt(), in.readInt(), in.readInt()
+ in.readInt(), in.readInt(), in.readInt(),
+ in.readInt(), in.readInt(), in.readInt(),
+ in.readBoolean()
);
}
@@ -304,4 +322,30 @@
public int getRxLinkSpeedMbps() {
return mRxLinkSpeedMbps;
}
+
+ /** Cellular data network type currently in use on the device for data transmission */
+ @NetworkType public int getCellularDataNetworkType() {
+ return mCellularDataNetworkType;
+ }
+
+ /**
+ * Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+ * CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+ */
+ public int getCellularSignalStrengthDbm() {
+ return mCellularSignalStrengthDbm;
+ }
+
+ /**
+ * Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+ * CDMA: Ecio, EVDO: SNR, GSM: invalid
+ */
+ public int getCellularSignalStrengthDb() {
+ return mCellularSignalStrengthDb;
+ }
+
+ /** Whether the primary registered cell of current entry is same as that of previous entry */
+ public boolean getIsSameRegisteredCell() {
+ return mIsSameRegisteredCell;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index 8e37113..cd60f02 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -74,7 +74,8 @@
private static WifiUsabilityStatsEntry createResult() {
return new WifiUsabilityStatsEntry(
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, true
);
}
@@ -111,5 +112,10 @@
assertEquals(expected.getProbeMcsRateSinceLastUpdate(),
actual.getProbeMcsRateSinceLastUpdate());
assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps());
+ assertEquals(expected.getCellularDataNetworkType(), actual.getCellularDataNetworkType());
+ assertEquals(expected.getCellularSignalStrengthDbm(),
+ actual.getCellularSignalStrengthDbm());
+ assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb());
+ assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell());
}
}