Merge "Move ScanMessage to frontend package"
diff --git a/Android.bp b/Android.bp
index 0e9550a..477f027 100644
--- a/Android.bp
+++ b/Android.bp
@@ -268,6 +268,7 @@
":updatable-media-srcs",
":framework-mediaprovider-sources",
":framework-wifi-updatable-sources",
+ ":ike-srcs",
]
}
@@ -432,6 +433,7 @@
// TODO(b/146167933): Use framework-statsd-stubs
"framework-statsd",
"framework-wifi-stubs",
+ "ike-stubs",
],
installable: true,
javac_shard_size: 150,
@@ -486,6 +488,7 @@
"framework-statsd",
// TODO(b/140299412): should be framework-wifi-stubs
"framework-wifi",
+ "ike-stubs",
// TODO(jiyong): add more stubs for APEXes here
],
sdk_version: "core_platform",
@@ -1134,6 +1137,7 @@
srcs: [
":framework-annotations",
"core/java/android/net/InterfaceConfiguration.java",
+ "core/java/android/os/BasicShellCommandHandler.java",
"core/java/android/os/HandlerExecutor.java",
"core/java/android/util/BackupUtils.java",
"core/java/android/util/LocalLog.java",
diff --git a/apex/blobstore/OWNERS b/apex/blobstore/OWNERS
new file mode 100644
index 0000000..8e04399
--- /dev/null
+++ b/apex/blobstore/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+
+sudheersai@google.com
+yamasani@google.com
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
new file mode 100644
index 0000000..4dc0c49
--- /dev/null
+++ b/apex/blobstore/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsBlobStoreTestCases"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 05583677..dec5634 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -85,4 +85,44 @@
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
+
+ /**
+ * Returns the most recently registered experiment IDs.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ long[] getRegisteredExperimentIds();
+
+ /**
+ * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getMetadata(in String packageName);
+
+ /**
+ * Fetches data for the specified configuration key. Returns a byte array representing proto
+ * wire-encoded of ConfigMetricsReportList.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getData(in long key, in String packageName);
+
+ /**
+ * Sets a configuration with the specified config id and subscribes to updates for this
+ * configuration id. Broadcasts will be sent if this configuration needs to be collected.
+ * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
+ * registered in a separate function.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void addConfiguration(in long configId, in byte[] config, in String packageName);
+
+ /**
+ * Removes the configuration with the matching config id. No-op if this config id does not
+ * exist.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void removeConfiguration(in long configId, in String packageName);
}
\ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 9358439..c409f51 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -89,24 +89,24 @@
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getData(in long key, in String packageName);
+ byte[] getData(in long key, int callingUid);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getMetadata(in String packageName);
+ byte[] getMetadata();
/**
- * Sets a configuration with the specified config key and subscribes to updates for this
+ * Sets a configuration with the specified config id and subscribes to updates for this
* configuration key. Broadcasts will be sent if this configuration needs to be collected.
* The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
* registered in a separate function.
*
* Requires Manifest.permission.DUMP.
*/
- void addConfiguration(in long configKey, in byte[] config, in String packageName);
+ void addConfiguration(in long configId, in byte[] config, in int callingUid);
/**
* Registers the given pending intent for this config key. This intent is invoked when the
@@ -143,12 +143,12 @@
void removeActiveConfigsChangedOperation(int callingUid);
/**
- * Removes the configuration with the matching config key. No-op if this config key does not
+ * Removes the configuration with the matching config id. No-op if this config id does not
* exist.
*
* Requires Manifest.permission.DUMP.
*/
- void removeConfiguration(in long configKey, in String packageName);
+ void removeConfiguration(in long configId, in int callingUid);
/**
* Set the PendingIntentRef to be used when broadcasting subscriber
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 1d03e3b..b27d0f7 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -19,6 +19,7 @@
import static com.android.server.stats.StatsCompanion.PendingIntentRef;
import android.Manifest;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
@@ -245,20 +246,127 @@
}
}
+ @Override
+ public long[] getRegisteredExperimentIds() throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getRegisteredExperimentIds();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to registerExperimentIds");
+ }
+
+ @Override
+ public byte[] getMetadata(String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getMetadata();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getMetadata with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getMetadata");
+ }
+
+ @Override
+ public byte[] getData(long key, String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getData(key, callingUid);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getData with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getData");
+ }
+
+ @Override
+ public void addConfiguration(long configId, byte[] config, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.addConfiguration(configId, config, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to addConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to addConfig");
+ }
+
+ @Override
+ public void removeConfiguration(long configId, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.removeConfiguration(configId, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to removeConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to removeConfig");
+ }
+
void setStatsCompanionService(StatsCompanionService statsCompanionService) {
mStatsCompanionService = statsCompanionService;
}
- private void enforceDumpAndUsageStatsPermission(String packageName) {
+ /**
+ * Checks that the caller has both DUMP and PACKAGE_USAGE_STATS permissions. Also checks that
+ * the caller has USAGE_STATS_PERMISSION_OPS for the specified packageName if it is not null.
+ *
+ * @param packageName The packageName to check USAGE_STATS_PERMISSION_OPS.
+ */
+ private void enforceDumpAndUsageStatsPermission(@Nullable String packageName) {
int callingUid = Binder.getCallingUid();
int callingPid = Binder.getCallingPid();
if (callingPid == Process.myPid()) {
return;
}
+
mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, null);
+ if (packageName == null) {
+ return;
+ }
AppOpsManager appOpsManager = (AppOpsManager) mContext
.getSystemService(Context.APP_OPS_SERVICE);
switch (appOpsManager.noteOp(USAGE_STATS_PERMISSION_OPS,
diff --git a/api/current.txt b/api/current.txt
index 51641f2..956a892 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25781,8 +25781,8 @@
method @Nullable public android.graphics.Bitmap getImageAtIndex(int);
method @Nullable public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
method @Nullable public android.graphics.Bitmap getPrimaryImage();
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public void release();
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -28683,6 +28683,7 @@
method public int getVideoWidth();
method public boolean isAudioDescription();
method public boolean isEncrypted();
+ method public boolean isHardOfHearing();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR;
field public static final int TYPE_AUDIO = 0; // 0x0
@@ -28699,6 +28700,7 @@
method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence);
method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean);
method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
+ method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean);
method public android.media.tv.TvTrackInfo.Builder setLanguage(String);
method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
@@ -29011,6 +29013,37 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
}
+ public class ConnectivityDiagnosticsManager {
+ method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+ }
+
+ public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+ method public void onConnectivityReport(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+ method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+ method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+ }
+
+ public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ field @NonNull public final android.os.PersistableBundle additionalInfo;
+ field @NonNull public final android.net.LinkProperties linkProperties;
+ field @NonNull public final android.net.Network network;
+ field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
+ field public final long reportTimestamp;
+ }
+
+ public static class ConnectivityDiagnosticsManager.DataStallReport {
+ ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle);
+ field public final int detectionMethod;
+ field @NonNull public final android.net.Network network;
+ field public final long reportTimestamp;
+ field @NonNull public final android.os.PersistableBundle stallDetails;
+ }
+
public class ConnectivityManager {
method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
@@ -30280,6 +30313,7 @@
@Deprecated public static class WifiConfiguration.AuthAlgorithm {
field @Deprecated public static final int LEAP = 2; // 0x2
field @Deprecated public static final int OPEN = 0; // 0x0
+ field @Deprecated public static final int SAE = 3; // 0x3
field @Deprecated public static final int SHARED = 1; // 0x1
field @Deprecated public static final String[] strings;
field @Deprecated public static final String varName = "auth_alg";
@@ -35682,7 +35716,9 @@
method public int describeContents();
method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String);
method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle);
+ method @NonNull public static android.os.PersistableBundle readFromStream(@NonNull java.io.InputStream) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException;
field @NonNull public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR;
field public static final android.os.PersistableBundle EMPTY;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 41ded16..4f26261 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -677,6 +677,7 @@
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
@@ -799,6 +800,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isOrganizationOwnedDeviceWithManagedProfile();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -1697,6 +1699,7 @@
field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
field public static final String TETHERING_SERVICE = "tethering";
field public static final String VR_SERVICE = "vrmanager";
+ field public static final String WIFI_COND_SERVICE = "wificond";
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
}
@@ -5927,6 +5930,7 @@
public class WifiManager {
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -6003,6 +6007,7 @@
field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
+ field public static final String EXTRA_WIFI_AP_FAILURE_REASON = "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
@@ -6291,6 +6296,10 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
}
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ method public boolean isAutoJoinEnabled();
+ }
+
public abstract class ProvisioningCallback {
ctor public ProvisioningCallback();
method public abstract void onProvisioningComplete();
@@ -7065,7 +7074,22 @@
}
public class TelephonyServiceManager {
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getCarrierConfigServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccCardControllerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccControllerService();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getIccPhoneBookServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getNetworkPolicyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getOpportunisticNetworkServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPackageManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPermissionManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPhoneSubServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSmsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSubscriptionServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyImsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRcsMessageServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRegistryServiceRegisterer();
method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getWindowServiceRegisterer();
}
public static class TelephonyServiceManager.ServiceNotFoundException extends java.lang.Exception {
@@ -7081,11 +7105,13 @@
public class UpdateEngine {
ctor public UpdateEngine();
+ method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]);
method public void applyPayload(String, long, long, String[]);
method public void applyPayload(@NonNull android.os.ParcelFileDescriptor, long, long, @NonNull String[]);
method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
method public boolean bind(android.os.UpdateEngineCallback);
method public void cancel();
+ method public int cleanupAppliedPayload();
method public void resetStatus();
method public void resume();
method public void suspend();
@@ -7093,14 +7119,21 @@
method public boolean verifyPayloadMetadata(String);
}
+ public static final class UpdateEngine.AllocateSpaceResult {
+ method public int errorCode();
+ method public long freeSpaceRequired();
+ }
+
public static final class UpdateEngine.ErrorCodeConstants {
ctor public UpdateEngine.ErrorCodeConstants();
+ field public static final int DEVICE_CORRUPTED = 61; // 0x3d
field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc
field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9
field public static final int ERROR = 1; // 0x1
field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4
field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7
field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8
+ field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c
field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
@@ -7913,7 +7946,71 @@
}
public static final class Telephony.SimInfo {
+ field public static final String ACCESS_RULES = "access_rules";
+ field public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = "access_rules_from_carrier_configs";
+ field public static final String CARD_ID = "card_id";
+ field public static final String CARRIER_ID = "carrier_id";
+ field public static final String CARRIER_NAME = "carrier_name";
+ field public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ field public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ field public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ field public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ field public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ field public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ field public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+ field public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ field public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ field public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ field public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ field public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ field public static final String COLOR = "color";
field @NonNull public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ field public static final String DATA_ROAMING = "data_roaming";
+ field public static final int DATA_ROAMING_DEFAULT = 0; // 0x0
+ field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
+ field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final String DISPLAY_NAME = "display_name";
+ field public static final String EHPLMNS = "ehplmns";
+ field public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ field public static final String GROUP_OWNER = "group_owner";
+ field public static final String GROUP_UUID = "group_uuid";
+ field public static final String HPLMNS = "hplmns";
+ field public static final String ICC_ID = "icc_id";
+ field public static final String IMSI = "imsi";
+ field public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ field public static final String IS_EMBEDDED = "is_embedded";
+ field public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ field public static final String IS_REMOVABLE = "is_removable";
+ field public static final String MCC = "mcc";
+ field public static final String MCC_STRING = "mcc_string";
+ field public static final String MNC = "mnc";
+ field public static final String MNC_STRING = "mnc_string";
+ field public static final String NAME_SOURCE = "name_source";
+ field public static final int NAME_SOURCE_CARRIER = 3; // 0x3
+ field public static final int NAME_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int NAME_SOURCE_SIM_PNN = 4; // 0x4
+ field public static final int NAME_SOURCE_SIM_SPN = 1; // 0x1
+ field public static final int NAME_SOURCE_USER_INPUT = 2; // 0x2
+ field public static final String NUMBER = "number";
+ field public static final String PROFILE_CLASS = "profile_class";
+ field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+ field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+ field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+ field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+ field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
+ field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
+ field public static final String SIM_SLOT_INDEX = "sim_id";
+ field public static final String SUBSCRIPTION_TYPE = "subscription_type";
+ field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+ field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
+ field public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ field public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ field public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ field public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ field public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ field public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ field public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
}
public static final class Telephony.Sms.Intents {
@@ -9180,30 +9277,37 @@
public abstract class CellIdentity implements android.os.Parcelable {
method @NonNull public abstract android.telephony.CellLocation asCellLocation();
+ method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo();
}
public final class CellIdentityCdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo();
}
public final class CellIdentityGsm extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo();
}
public final class CellIdentityLte extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo();
}
public final class CellIdentityNr extends android.telephony.CellIdentity {
method @NonNull public android.telephony.CellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo();
}
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo();
}
public final class CellIdentityWcdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
}
public final class DataFailCause {
@@ -10381,6 +10485,20 @@
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
}
+ public final class WapPushManagerConnector {
+ ctor public WapPushManagerConnector(@NonNull android.content.Context);
+ method public boolean bindToWapPushManagerService();
+ method @Nullable public String getConnectedWapPushManagerServicePackage();
+ method public int processMessage(@NonNull String, @NonNull String, @NonNull android.content.Intent);
+ method public void unbindWapPushManagerService();
+ field public static final int RESULT_APP_QUERY_FAILED = 2; // 0x2
+ field public static final int RESULT_EXCEPTION_CAUGHT = 16; // 0x10
+ field public static final int RESULT_FURTHER_PROCESSING = 32768; // 0x8000
+ field public static final int RESULT_INVALID_RECEIVER_NAME = 8; // 0x8
+ field public static final int RESULT_MESSAGE_HANDLED = 1; // 0x1
+ field public static final int RESULT_SIGNATURE_NO_MATCH = 4; // 0x4
+ }
+
}
package android.telephony.cdma {
diff --git a/api/test-current.txt b/api/test-current.txt
index 9967942..e64cbdb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -437,6 +437,7 @@
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7b96ce9..118a508 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -126,29 +126,28 @@
],
static_libs: [
- "libhealthhalutils",
- "libplatformprotos",
- ],
-
- shared_libs: [
"android.frameworks.stats@1.0",
- "android.hardware.health@2.0",
"android.hardware.power.stats@1.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"libbase",
- "libbinder",
"libcutils",
+ "libhealthhalutils",
+ "liblog",
+ "libplatformprotos",
+ "libprotoutil",
+ "libstatslog",
+ "libstatssocket",
+ "libsysutils",
+ ],
+ shared_libs: [
+ "android.hardware.health@2.0",
+ "libbinder",
"libgraphicsenv",
"libhidlbase",
"libincident",
- "liblog",
- "libprotoutil",
"libservices",
- "libstatslog",
"libstatsmetadata",
- "libstatssocket",
- "libsysutils",
"libtimestats_proto",
"libutils",
],
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 5ff0f97..1ca19c3 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1135,12 +1135,11 @@
}
}
-Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
- ConfigKey configKey(ipc->getCallingUid(), key);
+ VLOG("StatsService::getData with Uid %i", callingUid);
+ ConfigKey configKey(callingUid, key);
// The dump latency does not matter here since we do not include the current bucket, we do not
// need to pull any new data anyhow.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
@@ -1148,22 +1147,18 @@
return Status::ok();
}
-Status StatsService::getMetadata(const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getMetadata(vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
- ipc->getCallingUid());
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
return Status::ok();
}
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
- const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+ const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
+ if (addConfigurationChecked(callingUid, key, config)) {
return Status::ok();
} else {
ALOGE("Could not parse malformatted StatsdConfig");
@@ -1228,13 +1223,11 @@
return Status::ok();
}
-Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- ConfigKey configKey(ipc->getCallingUid(), key);
+ ConfigKey configKey(callingUid, key);
mConfigManager->RemoveConfig(configKey);
- SubscriberReporter::getInstance().removeConfig(configKey);
return Status::ok();
}
@@ -1477,17 +1470,7 @@
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
-
- // Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
- }
- if (!checkCallingPermission(String16(kPermissionUsage))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
- }
+ ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
// Read the latest train info
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 0565f3c..c9a9072 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -99,15 +99,14 @@
* Binder call for clients to request data for this configuration key.
*/
virtual Status getData(int64_t key,
- const String16& packageName,
+ const int32_t callingUid,
vector<uint8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
- virtual Status getMetadata(const String16& packageName,
- vector<uint8_t>* output) override;
+ virtual Status getMetadata(vector<uint8_t>* output) override;
/**
@@ -116,7 +115,7 @@
*/
virtual Status addConfiguration(int64_t key,
const vector<uint8_t>& config,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
@@ -146,7 +145,7 @@
* Binder call to allow clients to remove the specified configuration.
*/
virtual Status removeConfiguration(int64_t key,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to associate the given config's subscriberId with the given pendingIntentRef.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 55d73c1..972adf7 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -189,25 +189,11 @@
// Remove from map
uidIt->second.erase(key);
- // No more configs for this uid, lets remove the active configs callback.
- if (uidIt->second.empty()) {
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
- }
- }
-
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
}
- auto itReceiver = mConfigReceivers.find(key);
- if (itReceiver != mConfigReceivers.end()) {
- // Remove from map
- mConfigReceivers.erase(itReceiver);
- }
-
// Remove from disk. There can still be a lingering file on disk so we check
// whether or not the config was on memory.
remove_saved_configs(key);
@@ -238,12 +224,6 @@
// Remove from map
remove_saved_configs(*it);
removed.push_back(*it);
- mConfigReceivers.erase(*it);
- }
-
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
}
mConfigs.erase(uidIt);
@@ -277,8 +257,6 @@
uidIt = mConfigs.erase(uidIt);
}
- mConfigReceivers.clear();
- mActiveConfigsChangedReceivers.clear();
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 35c6d37..e85b975 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -207,10 +207,7 @@
&linkedConditionDimensionKey);
if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
trueConditionDimensions.end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(
- currentUnSlicedPartCondition, eventTime);
- }
+ whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
}
}
} else {
@@ -222,15 +219,11 @@
&linkedConditionDimensionKey);
if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
dimensionsChangedToTrue->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(true, eventTime);
- }
+ whatIt.second->onConditionChanged(true, eventTime);
}
if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
dimensionsChangedToFalse->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(false, eventTime);
- }
+ whatIt.second->onConditionChanged(false, eventTime);
}
}
}
@@ -247,9 +240,7 @@
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
- }
+ whatIt.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
}
}
@@ -283,18 +274,14 @@
}
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
} else if (mIsActive) {
flushIfNeededLocked(eventTimeNs);
onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
} else { // mConditionSliced == true && !mIsActive
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
}
}
@@ -310,9 +297,7 @@
flushIfNeededLocked(eventTime);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(conditionMet, eventTime);
- }
+ whatIt.second->onConditionChanged(conditionMet, eventTime);
}
}
@@ -425,19 +410,11 @@
const int64_t& nextBucketStartTimeNs) {
for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
- for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
- if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s", whatIt->first.toString().c_str(),
- it->first.toString().c_str());
- it = whatIt->second.erase(it);
- } else {
- ++it;
- }
- }
- if (whatIt->second.empty()) {
+ if (whatIt->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
+ VLOG("erase bucket for key %s", whatIt->first.toString().c_str());
whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
} else {
- whatIt++;
+ ++whatIt;
}
}
StatsdStats::getInstance().noteBucketCount(mMetricId);
@@ -453,35 +430,15 @@
(unsigned long)mCurrentSlicedDurationTrackerMap.size());
if (verbose) {
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (const auto& slice : whatIt.second) {
- fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
- slice.first.toString().c_str());
- slice.second->dumpStates(out, verbose);
- }
+ fprintf(out, "\t(what)%s\n", whatIt.first.toString().c_str());
+ whatIt.second->dumpStates(out, verbose);
}
}
}
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
- if (stateIt != whatIt->second.end()) {
- return false;
- }
- if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
- size_t newTupleCount = whatIt->second.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionInConditionSize(
- mConfigKey, mMetricId, newTupleCount);
- // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
- if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("DurationMetric %lld dropping data for state values key %s",
- (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
- StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
- return true;
- }
- }
- } else {
+ if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
@@ -503,24 +460,16 @@
const ConditionKey& conditionKeys,
bool condition, const LogEvent& event) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
- const auto& stateKey = eventKey.getStateValuesKey();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- } else {
- if (whatIt->second.find(stateKey) == whatIt->second.end()) {
- if (hitGuardRailLocked(eventKey)) {
- return;
- }
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- }
+ mCurrentSlicedDurationTrackerMap[whatKey] = createDurationTracker(eventKey);
}
- auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
+ auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (mUseWhatDimensionAsInternalDimension) {
it->second->noteStart(whatKey, condition,
event.GetElapsedTimestampNs(), conditionKeys);
@@ -560,18 +509,14 @@
// Handles Stopall events.
if (matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->noteStopAll(event.GetElapsedTimestampNs());
- }
+ whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
}
return;
}
- HashableDimensionKey dimensionInWhat;
+ HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
if (!mDimensionsInWhat.empty()) {
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
- } else {
- dimensionInWhat = DEFAULT_DIMENSION_KEY;
}
// Handles Stop events.
@@ -579,9 +524,7 @@
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
- }
+ whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -593,10 +536,7 @@
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
- false);
- }
+ whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -619,8 +559,8 @@
condition = condition && mIsActive;
- handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY), conditionKey,
+ condition, event);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 45908fb..06da0f6 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -132,8 +132,7 @@
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The duration trackers in the current bucket.
- std::unordered_map<HashableDimensionKey,
- std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>>
+ std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
mCurrentSlicedDurationTrackerMap;
// Helper function to create a duration tracker given the metric aggregation type.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 6b5c299..afe93d4 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -82,8 +82,6 @@
virtual ~DurationTracker(){};
- virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0;
-
virtual void noteStart(const HashableDimensionKey& key, bool condition,
const int64_t eventTime, const ConditionKey& conditionKey) = 0;
virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index df66cb0..2be5855 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -37,24 +37,6 @@
conditionSliced, fullLink, anomalyTrackers) {
}
-unique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<MaxDurationTracker>(*this);
- for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end();) {
- if (it->second.state != kStopped) {
- it->second.lastStartTime = eventTime;
- it->second.lastDuration = 0;
- it++;
- } else {
- it = clonedTracker->mInfos.erase(it);
- }
- }
- if (clonedTracker->mInfos.empty()) {
- return nullptr;
- } else {
- return clonedTracker;
- }
-}
-
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
if (mInfos.find(newKey) != mInfos.end()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index d0371da..efb8dc7 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -38,8 +38,6 @@
MaxDurationTracker(const MaxDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index b0fd975..57f3965 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -38,13 +38,6 @@
mLastStartTime = 0;
}
-unique_ptr<DurationTracker> OringDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<OringDurationTracker>(*this);
- clonedTracker->mLastStartTime = eventTime;
- clonedTracker->mDuration = 0;
- return clonedTracker;
-}
-
bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 43c48d5..c3aad66 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -37,8 +37,6 @@
OringDurationTracker(const OringDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index a9a105f..a37cad1 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -69,12 +69,6 @@
}
}
-void SubscriberReporter::removeConfig(const ConfigKey& configKey) {
- VLOG("SubscriberReporter::removeConfig called.");
- lock_guard<std::mutex> lock(mLock);
- mIntentMap.erase(configKey);
-}
-
void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
const Subscription& subscription,
const MetricDimensionKey& dimKey) const {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 8ccc8ee..087a1b8 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -59,9 +59,6 @@
*/
void unsetBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
- /** Remove all information stored by SubscriberReporter about the given config. */
- void removeConfig(const ConfigKey& configKey);
-
/**
* Sends a broadcast via the intentSender previously stored for the
* given (configKey, subscriberId) pair by setBroadcastSubscriber.
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 0bc3ebb..16b51d9 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -28,16 +28,16 @@
#ifdef __ANDROID__
-const string kAndroid = "android";
const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
+const int kCallingUid = 0; // Randomly chosen
void SendConfig(StatsService& service, const StatsdConfig& config) {
string str;
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
- service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
+ service.addConfiguration(kConfigKey, configAsVec, kCallingUid);
}
ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
@@ -50,7 +50,7 @@
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
- return reports.reports(0);
+ return reports.reports(kCallingUid);
}
StatsdConfig MakeConfig() {
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 83d1de6..8426374 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -157,11 +157,11 @@
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when adding configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when adding configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -194,10 +194,10 @@
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when removing configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when removing configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -390,10 +390,10 @@
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting data");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting data");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -427,10 +427,10 @@
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting metadata");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting metadata");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -462,21 +462,19 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
if (service == null) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
- }
- return new long[0];
+ throw new StatsUnavailableException("Failed to find statsmanager when "
+ + "getting experiment IDs");
}
return service.getRegisteredExperimentIds();
} catch (RemoteException e) {
if (DEBUG) {
Slog.d(TAG,
- "Failed to connect to StatsCompanionService when getting "
+ "Failed to connect to StatsManagerService when getting "
+ "registered experiment IDs");
}
- return new long[0];
+ throw new StatsUnavailableException("could not connect", e);
}
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index a1765c8..078e453 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -153,6 +153,11 @@
*/
public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS;
+ /**
+ * disable flags to be applied when the device is sim-locked.
+ */
+ private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND;
+
/** @hide */
public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0;
/** @hide */
@@ -385,6 +390,30 @@
}
/**
+ * Enable or disable expansion of the status bar. When the device is SIM-locked, the status
+ * bar should not be expandable.
+ *
+ * @param disabled If {@code true}, the status bar will be set to non-expandable. If
+ * {@code false}, re-enables expansion of the status bar.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ public void setDisabledForSimNetworkLock(boolean disabled) {
+ try {
+ final int userId = Binder.getCallingUserHandle().getIdentifier();
+ final IStatusBarService svc = getService();
+ if (svc != null) {
+ svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE,
+ mToken, mContext.getPackageName(), userId);
+ }
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get this app's currently requested disabled components
*
* @return a new DisableInfo
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f3028a1..2aac94c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -88,7 +88,6 @@
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
@@ -6757,6 +6756,34 @@
}
/**
+ * @hide
+ * Privileged apps can use this method to find out if the device was provisioned as
+ * organization-owend device with a managed profile.
+ *
+ * This, together with checking whether the device has a device owner (by calling
+ * {@link #isDeviceManaged()}), could be used to learn whether the device is owned by an
+ * organization or an individual:
+ * If this method returns true OR {@link #isDeviceManaged()} returns true, then
+ * the device is owned by an organization. Otherwise, it's owned by an individual.
+ *
+ * @return {@code true} if the device was provisioned as organization-owned device,
+ * {@code false} otherwise.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ throwIfParentInstance("isOrganizationOwnedDeviceWithManagedProfile");
+ if (mService != null) {
+ try {
+ return mService.isOrganizationOwnedDeviceWithManagedProfile();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns whether the specified package can read the device identifiers.
*
* @param packageName The package name of the app to check for device identifier access.
@@ -11215,12 +11242,12 @@
* #setCrossProfilePackages(ComponentName, Set)}.</li>
* <li>The default package names set by the OEM that are allowed to request user consent for
* cross-profile communication without being explicitly enabled by the admin, via
- * {@link R.array#cross_profile_apps}</li>
+ * {@link com.android.internal.R.array#cross_profile_apps}</li>
* </ul>
*
* @return the combined set of whitelisted package names set via
* {@link #setCrossProfilePackages(ComponentName, Set)} and
- * {@link R.array#cross_profile_apps}
+ * {@link com.android.internal.R.array#cross_profile_apps}
*
* @hide
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 55dfe2f..3eec46b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -156,6 +156,7 @@
void setProfileName(in ComponentName who, String profileName);
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean isOrganizationOwnedDeviceWithManagedProfile();
boolean checkDeviceIdentifierAccess(in String packageName, int pid, int uid);
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 55f92be..50de7385 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index 4c55ba1..17e9c5a 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 4a89a12..479e4b4 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index af9ece0..54dd1be 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -24,8 +24,8 @@
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.util.Log;
-import android.util.TimestampedValue;
/**
* The interface through which system components can send signals to the TimeDetectorService.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a28868e..8dd9381 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4016,6 +4016,7 @@
* @see android.net.wifi.WifiCondManager
* @hide
*/
+ @SystemApi
public static final String WIFI_COND_SERVICE = "wificond";
/**
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
new file mode 100644
index 0000000..6afdb5e
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -0,0 +1,242 @@
+/*
+ * 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.IntDef;
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * Class that provides utilities for collecting network connectivity diagnostics information.
+ * Connectivity information is made available through triggerable diagnostics tools and by listening
+ * to System validations. Some diagnostics information may be permissions-restricted.
+ *
+ * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
+ * connectivity on a user device. These tools will provide several mechanisms for these applications
+ * to be alerted to network conditions as well as diagnose potential network issues themselves.
+ *
+ * <p>The primary responsibilities of this class are to:
+ *
+ * <ul>
+ * <li>Allow permissioned applications to register and unregister callbacks for network event
+ * notifications
+ * <li>Invoke callbacks for network event notifications, including:
+ * <ul>
+ * <li>Network validations
+ * <li>Data stalls
+ * <li>Connectivity reports from applications
+ * </ul>
+ * </ul>
+ */
+public class ConnectivityDiagnosticsManager {
+ public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+ public static final int DETECTION_METHOD_TCP_METRICS = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"DETECTION_METHOD_"},
+ value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
+ public @interface DetectionMethod {}
+
+ /** @hide */
+ public ConnectivityDiagnosticsManager() {}
+
+ /** Class that includes connectivity information for a specific Network at a specific time. */
+ public static class ConnectivityReport {
+ /** The Network for which this ConnectivityReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** LinkProperties available on the Network at the reported timestamp */
+ @NonNull public final LinkProperties linkProperties;
+
+ /** NetworkCapabilities available on the Network at the reported timestamp */
+ @NonNull public final NetworkCapabilities networkCapabilities;
+
+ /** PersistableBundle that may contain additional info about the report */
+ @NonNull public final PersistableBundle additionalInfo;
+
+ /**
+ * Constructor for ConnectivityReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onConnectivityReport} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this ConnectivityReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param linkProperties The LinkProperties available on network at reportTimestamp
+ * @param networkCapabilities The NetworkCapabilities available on network at
+ * reportTimestamp
+ * @param additionalInfo A PersistableBundle that may contain additional info about the
+ * report
+ */
+ public ConnectivityReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull PersistableBundle additionalInfo) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.linkProperties = linkProperties;
+ this.networkCapabilities = networkCapabilities;
+ this.additionalInfo = additionalInfo;
+ }
+ }
+
+ /** Class that includes information for a suspected data stall on a specific Network */
+ public static class DataStallReport {
+ /** The Network for which this DataStallReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** The detection method used to identify the suspected data stall */
+ @DetectionMethod public final int detectionMethod;
+
+ /** PersistableBundle that may contain additional information on the suspected data stall */
+ @NonNull public final PersistableBundle stallDetails;
+
+ /**
+ * Constructor for DataStallReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this DataStallReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param detectionMethod The detection method used to identify this data stall
+ * @param stallDetails A PersistableBundle that may contain additional info about the report
+ */
+ public DataStallReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @DetectionMethod int detectionMethod,
+ @NonNull PersistableBundle stallDetails) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.detectionMethod = detectionMethod;
+ this.stallDetails = stallDetails;
+ }
+ }
+
+ /**
+ * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
+ * network connectivity events. Must be extended by applications wanting notifications.
+ */
+ public abstract static class ConnectivityDiagnosticsCallback {
+ /**
+ * Called when the platform completes a data connectivity check. This will also be invoked
+ * upon registration with the latest report.
+ *
+ * <p>The Network specified in the ConnectivityReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The ConnectivityReport containing information about a connectivity check
+ */
+ public void onConnectivityReport(@NonNull ConnectivityReport report) {}
+
+ /**
+ * Called when the platform suspects a data stall on some Network.
+ *
+ * <p>The Network specified in the DataStallReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The DataStallReport containing information about the suspected data stall
+ */
+ public void onDataStallSuspected(@NonNull DataStallReport report) {}
+
+ /**
+ * Called when any app reports connectivity to the System.
+ *
+ * @param network The Network for which connectivity has been reported
+ * @param hasConnectivity The connectivity reported to the System
+ */
+ public void onNetworkConnectivityReported(
+ @NonNull Network network, boolean hasConnectivity) {}
+ }
+
+ /**
+ * Registers a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>Only apps that offer network connectivity to the user are allowed to register callbacks.
+ * This includes:
+ *
+ * <ul>
+ * <li>Carrier apps with active subscriptions
+ * <li>Active VPNs
+ * <li>WiFi Suggesters
+ * </ul>
+ *
+ * <p>Callbacks will be limited to receiving notifications for networks over which apps provide
+ * connectivity.
+ *
+ * <p>If a registering app loses its relevant permissions, any callbacks it registered will
+ * silently stop receiving callbacks.
+ *
+ * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If
+ * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException
+ * will be thrown.
+ *
+ * @param request The NetworkRequest that will be used to match with Networks for which
+ * callbacks will be fired
+ * @param e The Executor to be used for running the callback method invocations
+ * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
+ * System
+ * @throws IllegalArgumentException if the same callback instance is registered with multiple
+ * NetworkRequests
+ * @throws SecurityException if the caller does not have appropriate permissions to register a
+ * callback
+ */
+ public void registerConnectivityDiagnosticsCallback(
+ @NonNull NetworkRequest request,
+ @NonNull Executor e,
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+
+ /**
+ * Unregisters a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>If the given callback is not currently registered with the System, this operation will be
+ * a no-op.
+ *
+ * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
+ */
+ public void unregisterConnectivityDiagnosticsCallback(
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+}
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index b40283f..7a837e1 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -16,17 +16,24 @@
package android.os;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
/**
@@ -339,4 +346,44 @@
proto.end(token);
}
+
+ /**
+ * Writes the content of the {@link PersistableBundle} to a {@link OutputStream}.
+ *
+ * <p>The content can be read by a {@link #readFromStream}.
+ *
+ * @see #readFromStream
+ */
+ public void writeToStream(@NonNull OutputStream outputStream) throws IOException {
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(outputStream, UTF_8.name());
+ serializer.startTag(null, "bundle");
+ try {
+ saveToXml(serializer);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ serializer.endTag(null, "bundle");
+ serializer.flush();
+ }
+
+ /**
+ * Reads a {@link PersistableBundle} from an {@link InputStream}.
+ *
+ * <p>The stream must be generated by {@link #writeToStream}.
+ *
+ * @see #writeToStream
+ */
+ @NonNull
+ public static PersistableBundle readFromStream(@NonNull InputStream inputStream)
+ throws IOException {
+ try {
+ XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+ parser.setInput(inputStream, UTF_8.name());
+ parser.next();
+ return PersistableBundle.restoreFromXml(parser);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java
index 1211dd6..064cf7d 100644
--- a/core/java/android/os/TelephonyServiceManager.java
+++ b/core/java/android/os/TelephonyServiceManager.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
/**
* Provides a way to register and obtain the system service binder objects managed by the telephony
@@ -51,8 +52,8 @@
/**
* Register a system server binding object for a service.
*/
- public void register(@NonNull IBinder binder) {
- ServiceManager.addService(mServiceName, binder);
+ public void register(@NonNull IBinder service) {
+ ServiceManager.addService(mServiceName, service);
}
/**
@@ -114,25 +115,123 @@
*/
@NonNull
public ServiceRegisterer getTelephonyServiceRegisterer() {
- return new ServiceRegisterer("phone");
+ return new ServiceRegisterer(Context.TELEPHONY_SERVICE);
}
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony registry service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRegistryServiceRegisterer() {
+ return new ServiceRegisterer("telephony.registry");
+ }
-// TODO: Add more services...
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "subscription" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSubscriptionServiceRegisterer() {
-// return new ServiceRegisterer("isub");
-// }
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "SMS" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSmsServiceRegisterer() {
-// return new ServiceRegisterer("isms");
-// }
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony IMS service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyImsServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_IMS_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony RCS message service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRcsMessageServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_RCS_MESSAGE_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the subscription service.
+ */
+ @NonNull
+ public ServiceRegisterer getSubscriptionServiceRegisterer() {
+ return new ServiceRegisterer("isub");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the network policy service.
+ */
+ @NonNull
+ public ServiceRegisterer getNetworkPolicyServiceRegisterer() {
+ return new ServiceRegisterer(Context.NETWORK_POLICY_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the phone sub service.
+ */
+ @NonNull
+ public ServiceRegisterer getPhoneSubServiceRegisterer() {
+ return new ServiceRegisterer("iphonesubinfo");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the opportunistic network service.
+ */
+ @NonNull
+ public ServiceRegisterer getOpportunisticNetworkServiceRegisterer() {
+ return new ServiceRegisterer("ions");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the carrier config service.
+ */
+ @NonNull
+ public ServiceRegisterer getCarrierConfigServiceRegisterer() {
+ return new ServiceRegisterer(Context.CARRIER_CONFIG_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "SMS" service.
+ */
+ @NonNull
+ public ServiceRegisterer getSmsServiceRegisterer() {
+ return new ServiceRegisterer("isms");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the eUICC controller service.
+ */
+ @NonNull
+ public ServiceRegisterer getEuiccControllerService() {
+ return new ServiceRegisterer("econtroller");
+ }
+
+ @NonNull
+ public ServiceRegisterer getEuiccCardControllerServiceRegisterer() {
+ return new ServiceRegisterer("euicc_card_controller");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the package manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPackageManagerServiceRegisterer() {
+ return new ServiceRegisterer("package");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the permission manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPermissionManagerServiceRegisterer() {
+ return new ServiceRegisterer("permissionmgr");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the ICC phone book service.
+ */
+ @NonNull
+ public ServiceRegisterer getIccPhoneBookServiceRegisterer() {
+ return new ServiceRegisterer("simphonebook");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the window service.
+ */
+ @NonNull
+ public ServiceRegisterer getWindowServiceRegisterer() {
+ return new ServiceRegisterer(Context.WINDOW_SERVICE);
+ }
}
diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
similarity index 97%
rename from core/java/android/util/TimestampedValue.java
rename to core/java/android/os/TimestampedValue.java
index 4505673..348574e 100644
--- a/core/java/android/util/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -14,13 +14,10 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
import java.util.Objects;
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index a9ddffe..16f7b39 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.IUpdateEngine;
@@ -140,8 +141,43 @@
* {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
*/
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
+
+ /**
+ * Error code: there is not enough space on the device to apply the update. User should
+ * be prompted to free up space and re-try the update.
+ *
+ * <p>See {@link UpdateEngine#allocateSpace}.
+ */
+ public static final int NOT_ENOUGH_SPACE = 60;
+
+ /**
+ * Error code: the device is corrupted and no further updates may be applied.
+ *
+ * <p>See {@link UpdateEngine#cleanupAppliedPayload}.
+ */
+ public static final int DEVICE_CORRUPTED = 61;
}
+ /** @hide */
+ @IntDef(value = {
+ ErrorCodeConstants.SUCCESS,
+ ErrorCodeConstants.ERROR,
+ ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
+ ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+ ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+ ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+ ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
+ ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+ ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+ ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+ ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+ ErrorCodeConstants.NOT_ENOUGH_SPACE,
+ ErrorCodeConstants.DEVICE_CORRUPTED,
+ })
+ public @interface ErrorCode {}
+
/**
* Status codes for update engine. Values must agree with the ones in
* {@code system/update_engine/client_library/include/update_engine/update_status.h}.
@@ -419,4 +455,138 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Return value of {@link #allocateSpace.}
+ */
+ public static final class AllocateSpaceResult {
+ private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS;
+ private long mFreeSpaceRequired = 0;
+ private AllocateSpaceResult() {}
+ /**
+ * Error code.
+ *
+ * @return The following error codes:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated
+ * successfully.</li>
+ * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient
+ * space.</li>
+ * <li>Other {@link ErrorCodeConstants} for other errors.</li>
+ * </ul>
+ */
+ @ErrorCode
+ public int errorCode() {
+ return mErrorCode;
+ }
+
+ /**
+ * Estimated total space that needs to be available on the userdata partition to apply the
+ * payload (in bytes).
+ *
+ * <p>
+ * Note that in practice, more space needs to be made available before applying the payload
+ * to keep the device working.
+ *
+ * @return The following values:
+ * <ul>
+ * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li>
+ * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}.
+ * Value is the estimated total space required on userdata partition.</li>
+ * </ul>
+ * @throws IllegalStateException if {@link #errorCode} is not one of the above.
+ *
+ */
+ public long freeSpaceRequired() {
+ if (mErrorCode == ErrorCodeConstants.SUCCESS) {
+ return 0;
+ }
+ if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) {
+ return mFreeSpaceRequired;
+ }
+ throw new IllegalStateException(String.format(
+ "freeSpaceRequired() is not available when error code is %d", mErrorCode));
+ }
+ }
+
+ /**
+ * Initialize partitions for a payload associated with the given payload
+ * metadata {@code payloadMetadataFilename} by preallocating required space.
+ *
+ * <p>This function should be called after payload has been verified after
+ * {@link #verifyPayloadMetadata}. This function does not verify whether
+ * the given payload is applicable or not.
+ *
+ * <p>Implementation of {@code allocateSpace} uses
+ * {@code headerKeyValuePairs} to determine whether space has been allocated
+ * for a different or same payload previously. If space has been allocated
+ * for a different payload before, space will be reallocated for the given
+ * payload. If space has been allocated for the same payload, no actions to
+ * storage devices are taken.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}.
+ * @param headerKeyValuePairs See {@link #applyPayload}.
+ * @return See {@link AllocateSpaceResult}.
+ */
+ @NonNull
+ public AllocateSpaceResult allocateSpace(
+ @NonNull String payloadMetadataFilename,
+ @NonNull String[] headerKeyValuePairs) {
+ AllocateSpaceResult result = new AllocateSpaceResult();
+ try {
+ result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload(
+ payloadMetadataFilename,
+ headerKeyValuePairs);
+ result.mErrorCode = result.mFreeSpaceRequired == 0
+ ? ErrorCodeConstants.SUCCESS
+ : ErrorCodeConstants.NOT_ENOUGH_SPACE;
+ return result;
+ } catch (ServiceSpecificException e) {
+ result.mErrorCode = e.errorCode;
+ result.mFreeSpaceRequired = 0;
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Cleanup files used by the previous update and free up space after the
+ * device has been booted successfully into the new build.
+ *
+ * <p>In particular, this function waits until delta files for snapshots for
+ * Virtual A/B update are merged to OS partitions, then delete these delta
+ * files.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * <p>This function does not delete payload binaries downloaded for a
+ * non-streaming OTA update.
+ *
+ * @return One of the following:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li>
+ * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred.
+ * The device should be able to recover after a reboot. The function should
+ * be retried after the reboot.</li>
+ * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is
+ * encountered. Device is corrupted, and future updates must not be applied.
+ * The device cannot recover without flashing and factory resets.
+ * </ul>
+ *
+ * @throws ServiceSpecificException if other transient errors has occurred.
+ * A reboot may or may not help resolving the issue.
+ */
+ @ErrorCode
+ public int cleanupAppliedPayload() {
+ try {
+ return mUpdateEngine.cleanupSuccessfulUpdate();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java
index f07294e..7fe7024 100644
--- a/core/java/android/os/UpdateEngineCallback.java
+++ b/core/java/android/os/UpdateEngineCallback.java
@@ -44,5 +44,6 @@
* unsuccessfully. The value of {@code errorCode} will be one of the
* values from {@link UpdateEngine.ErrorCodeConstants}.
*/
- public abstract void onPayloadApplicationComplete(int errorCode);
+ public abstract void onPayloadApplicationComplete(
+ @UpdateEngine.ErrorCode int errorCode);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bbaf94a..07cbcfb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -68,7 +68,6 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
-import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -12459,16 +12458,17 @@
/**
* Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
- * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ * value
+ * {@link android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
* <p>
* Type: int (0 for false, 1 for true)
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#ENHANCED_4G_MODE_ENABLED}
* instead.
*/
@Deprecated
public static final String ENHANCED_4G_MODE_ENABLED =
- SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
+ Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -12476,10 +12476,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#VT_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
+ public static final String VT_IMS_ENABLED = Telephony.SimInfo.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -12487,10 +12487,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
+ public static final String WFC_IMS_ENABLED = Telephony.SimInfo.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -12498,10 +12498,10 @@
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_MODE} instead.
*/
@Deprecated
- public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
+ public static final String WFC_IMS_MODE = Telephony.SimInfo.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -12509,11 +12509,11 @@
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_MODE}
* instead.
*/
@Deprecated
- public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
+ public static final String WFC_IMS_ROAMING_MODE = Telephony.SimInfo.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -12521,12 +12521,12 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_ENABLED}
* instead
*/
@Deprecated
public static final String WFC_IMS_ROAMING_ENABLED =
- SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
+ Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 1d9bdb8..2e7ac3f5 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -38,11 +38,13 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
+import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
import android.text.TextUtils;
import android.util.Patterns;
@@ -4980,5 +4982,402 @@
*/
@NonNull
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * TelephonyProvider unique key column name is the subscription id.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+ /**
+ * TelephonyProvider column name for a unique identifier for the subscription within the
+ * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+ * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * TelephonyProvider column name for user SIM_SlOT_INDEX
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_SLOT_INDEX = "sim_id";
+
+ /**
+ * SIM is not inserted
+ */
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * TelephonyProvider column name Subscription-type.
+ * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM
+ * Subscriptions, {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+ * Default value is 0.
+ */
+ public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+ /**
+ * This constant is to designate a subscription as a Local-SIM Subscription.
+ * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on
+ * the device.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+ /**
+ * This constant is to designate a subscription as a Remote-SIM Subscription.
+ * <p>
+ * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+ * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription
+ * can be used for SMS, Voice and data by proxying data through the connected device.
+ * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+ * </p>
+ *
+ * <p>
+ * A Remote-SIM is available only as long the phone stays connected to this device.
+ * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+ * no longer known. All data associated with the subscription, such as stored SMS, call
+ * logs, contacts etc, are removed from this device.
+ * </p>
+ *
+ * <p>
+ * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+ * the phone. The Subscription Id associated with the new subscription is different from
+ * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+ * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM
+ * that was never seen before.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+ /**
+ * TelephonyProvider column name data_enabled_override_rules.
+ * It's a list of rules for overriding data enabled settings. The syntax is
+ * For example, "mms=nonDefault" indicates enabling data for mms in non-default
+ * subscription.
+ * "default=nonDefault&inVoiceCall" indicates enabling data for internet in non-default
+ * subscription and while is in voice call.
+ *
+ * Default value is empty string.
+ */
+ public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+
+ /**
+ * TelephonyProvider column name for user displayed name.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * TelephonyProvider column name for the service provider name for the SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARRIER_NAME = "carrier_name";
+
+ /**
+ * TelephonyProvider column name for source of the user displayed name.
+ * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ /** The name_source is the default, which is from the carrier id. */
+ public static final int NAME_SOURCE_DEFAULT = 0;
+
+ /**
+ * The name_source is from SIM EF_SPN.
+ */
+ public static final int NAME_SOURCE_SIM_SPN = 1;
+
+ /**
+ * The name_source is from user input
+ */
+ public static final int NAME_SOURCE_USER_INPUT = 2;
+
+ /**
+ * The name_source is carrier (carrier app, carrier config, etc.)
+ */
+ public static final int NAME_SOURCE_CARRIER = 3;
+
+ /**
+ * The name_source is from SIM EF_PNN.
+ */
+ public static final int NAME_SOURCE_SIM_PNN = 4;
+
+ /**
+ * TelephonyProvider column name for the color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ /** TelephonyProvider column name for the default color of a SIM {@hide} */
+ public static final int COLOR_DEFAULT = 0;
+
+ /**
+ * TelephonyProvider column name for the phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * TelephonyProvider column name for the number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ /**
+ * TelephonyProvider column name for the default display format of a SIM
+ * @hide
+ */
+ public static final int DISPLAY_NUMBER_DEFAULT = 1;
+
+ /**
+ * TelephonyProvider column name for whether data roaming is enabled.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ /** Indicates that data roaming is enabled for a subscription */
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ /** Indicates that data roaming is disabled for a subscription */
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ /** TelephonyProvider column name for default data roaming setting: disable */
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ /**
+ * TelephonyProvider column name for subscription carrier id.
+ * @see TelephonyManager#getSimCarrierId()
+ * <p>Type: INTEGER (int) </p>
+ */
+ public static final String CARRIER_ID = "carrier_id";
+
+ /**
+ * A comma-separated list of EHPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String EHPLMNS = "ehplmns";
+
+ /**
+ * A comma-separated list of HPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String HPLMNS = "hplmns";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MCC_STRING = "mcc_string";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MNC_STRING = "mnc_string";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MCC = "mcc";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MNC = "mnc";
+
+ /**
+ * TelephonyProvider column name for the iso country code associated with a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ISO_COUNTRY_CODE = "iso_country_code";
+
+ /**
+ * TelephonyProvider column name for the sim provisioning status associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+
+ /** The sim is provisioned {@hide} */
+ public static final int SIM_PROVISIONED = 0;
+
+ /**
+ * TelephonyProvider column name for whether a subscription is embedded (that is, present on
+ * an eSIM).
+ * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+ */
+ public static final String IS_EMBEDDED = "is_embedded";
+
+ /**
+ * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of
+ * the current enabled profile on the card, while for eUICC card it is the EID of the card.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARD_ID = "card_id";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES = "access_rules";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+ * Only present if there are access rules in CarrierConfigs
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+ "access_rules_from_carrier_configs";
+
+ /**
+ * TelephonyProvider column name identifying whether an embedded subscription is on a
+ * removable card. Such subscriptions are marked inaccessible as soon as the current card
+ * is removed. Otherwise, they will remain accessible unless explicitly deleted. Only
+ * present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+ */
+ public static final String IS_REMOVABLE = "is_removable";
+
+ /** TelephonyProvider column name for extreme threat in CB settings */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /** TelephonyProvider column name for severe threat in CB settings */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /** TelephonyProvider column name for amber alert in CB settings */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /** TelephonyProvider column name for emergency alert in CB settings */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /** TelephonyProvider column name for alert sound duration in CB settings */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /** TelephonyProvider column name for alert reminder interval in CB settings */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /** TelephonyProvider column name for enabling vibrate in CB settings */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /** TelephonyProvider column name for enabling alert speech in CB settings */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /** TelephonyProvider column name for ETWS test alert in CB settings */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /** TelephonyProvider column name for enable channel50 alert in CB settings */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /** TelephonyProvider column name for CMAS test alert in CB settings */
+ public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+
+ /** TelephonyProvider column name for Opt out dialog in CB settings */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
+ * TelephonyProvider column name for enable Volte.
+ *
+ * If this setting is not initialized (set to -1) then we use the Carrier Config value
+ * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /** TelephonyProvider column name for enable VT (Video Telephony over IMS) */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /** TelephonyProvider column name for enable Wifi calling */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /** TelephonyProvider column name for Wifi calling mode */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /** TelephonyProvider column name for Wifi calling mode in roaming */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /** TelephonyProvider column name for enable Wifi calling in roaming */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is opportunistic, that is,
+ * whether the network it connects to is limited in functionality or coverage.
+ * For example, CBRS.
+ * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
+ */
+ public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+
+ /**
+ * TelephonyProvider column name for group ID. Subscriptions with same group ID
+ * are considered bundled together, and should behave as a single subscription at
+ * certain scenarios.
+ */
+ public static final String GROUP_UUID = "group_uuid";
+
+ /**
+ * TelephonyProvider column name for group owner. It's the package name who created
+ * the subscription group.
+ */
+ public static final String GROUP_OWNER = "group_owner";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is metered or not, that is,
+ * whether the network it connects to charges for subscription or not. For example, paid
+ * CBRS or unpaid.
+ * @hide
+ */
+ public static final String IS_METERED = "is_metered";
+
+ /**
+ * TelephonyProvider column name for the profile class of a subscription
+ * Only present if {@link #IS_EMBEDDED} is 1.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String PROFILE_CLASS = "profile_class";
+
+ /**
+ * A testing profile can be pre-loaded or downloaded onto
+ * the eUICC and provides connectivity to test equipment
+ * for the purpose of testing the device and the eUICC. It
+ * is not intended to store any operator credentials.
+ */
+ public static final int PROFILE_CLASS_TESTING = 0;
+
+ /**
+ * A provisioning profile is pre-loaded onto the eUICC and
+ * provides connectivity to a mobile network solely for the
+ * purpose of provisioning profiles.
+ */
+ public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+ /**
+ * An operational profile can be pre-loaded or downloaded
+ * onto the eUICC and provides services provided by the
+ * operator.
+ */
+ public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+ /**
+ * The profile class is unset. This occurs when profile class
+ * info is not available. The subscription either has no profile
+ * metadata or the profile metadata did not encode profile class.
+ */
+ public static final int PROFILE_CLASS_UNSET = -1;
+
+ /** Default profile class */
+ public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
+ /**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI = "imsi";
+
+ /** Whether uicc applications is set to be enabled or disabled. By default it's enabled. */
+ public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
}
}
diff --git a/core/java/android/telephony/WapPushManagerConnector.java b/core/java/android/telephony/WapPushManagerConnector.java
new file mode 100644
index 0000000..a9df506
--- /dev/null
+++ b/core/java/android/telephony/WapPushManagerConnector.java
@@ -0,0 +1,178 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.IWapPushManager;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * APIs for platform to connect to the WAP push manager service.
+ *
+ * <p>To start connection, {@link #bindToWapPushManagerService} should be called.
+ *
+ * <p>Upon completion {@link #unbindWapPushManagerService} should be called to unbind the service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class WapPushManagerConnector {
+ private final Context mContext;
+
+ private volatile WapPushManagerConnection mConnection;
+ private volatile IWapPushManager mWapPushManager;
+ private String mWapPushManagerPackage;
+
+ /**
+ * The {@link android.content.Intent} that must be declared as handled by the
+ * WAP push manager service.
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "com.android.internal.telephony.IWapPushManager";
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"RESULT_"}, value = {
+ RESULT_MESSAGE_HANDLED,
+ RESULT_APP_QUERY_FAILED,
+ RESULT_SIGNATURE_NO_MATCH,
+ RESULT_INVALID_RECEIVER_NAME,
+ RESULT_EXCEPTION_CAUGHT,
+ RESULT_FURTHER_PROCESSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProcessMessageResult{}
+
+ /** {@link #processMessage} return value: Message is handled. */
+ public static final int RESULT_MESSAGE_HANDLED = 0x1;
+ /** {@link #processMessage} return value: Application ID or content type was not found. */
+ public static final int RESULT_APP_QUERY_FAILED = 0x2;
+ /** {@link #processMessage} return value: Receiver application signature check failed. */
+ public static final int RESULT_SIGNATURE_NO_MATCH = 0x4;
+ /** {@link #processMessage} return value: Receiver application was not found. */
+ public static final int RESULT_INVALID_RECEIVER_NAME = 0x8;
+ /** {@link #processMessage} return value: Unknown exception. */
+ public static final int RESULT_EXCEPTION_CAUGHT = 0x10;
+ /** {@link #processMessage} return value: further processing needed. */
+ public static final int RESULT_FURTHER_PROCESSING = 0x8000;
+
+ /** The application package name of the WAP push manager service. */
+ private static final String SERVICE_PACKAGE = "com.android.smspush";
+
+ public WapPushManagerConnector(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Binds to the WAP push manager service. This method should be called exactly once.
+ *
+ * @return {@code true} upon successfully binding to a service, {@code false} otherwise
+ */
+ public boolean bindToWapPushManagerService() {
+ Preconditions.checkState(mConnection == null);
+
+ Intent intent = new Intent(SERVICE_INTERFACE);
+ ComponentName component = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(component);
+ mConnection = new WapPushManagerConnection();
+ if (component != null
+ && mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ mWapPushManagerPackage = component.getPackageName();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the package name of WAP push manager service application connected to,
+ * or {@code null} if not connected.
+ */
+ @Nullable
+ public String getConnectedWapPushManagerServicePackage() {
+ return mWapPushManagerPackage;
+ }
+
+ /**
+ * Processes WAP push message and triggers the {@code intent}.
+ *
+ * @see RESULT_MESSAGE_HANDLED
+ * @see RESULT_APP_QUERY_FAILED
+ * @see RESULT_SIGNATURE_NO_MATCH
+ * @see RESULT_INVALID_RECEIVER_NAME
+ * @see RESULT_EXCEPTION_CAUGHT
+ * @see RESULT_FURTHER_PROCESSING
+ */
+ @ProcessMessageResult
+ public int processMessage(
+ @NonNull String applicationId, @NonNull String contentType, @NonNull Intent intent) {
+ try {
+ return mWapPushManager.processMessage(applicationId, contentType, intent);
+ } catch (NullPointerException | RemoteException e) {
+ return RESULT_EXCEPTION_CAUGHT;
+ }
+ }
+
+ /**
+ * Unbinds the WAP push manager service. This method should be called exactly once.
+ */
+ public void unbindWapPushManagerService() {
+ Preconditions.checkNotNull(mConnection);
+
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+
+ private class WapPushManagerConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Because we have bound to an explicit
+ // service that is running in our own process, we can
+ // cast its IBinder to a concrete class and directly access it.
+ mWapPushManager = IWapPushManager.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mWapPushManager = null;
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+ }
+}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 3f679bba..f324113 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -387,6 +387,26 @@
public static native int println_native(int bufID, int priority, String tag, String msg);
/**
+ * Send a log message to the "radio" log buffer, which can be dumped with
+ * {@code adb logcat -b radio}.
+ *
+ * <p>Only the telephony mainline module should use it.
+ *
+ * <p>Note ART will protect {@code MODULE_LIBRARIES} system APIs from regular app code.
+ *
+ * @param priority Log priority.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param message The message you would like logged.
+ * @hide
+ */
+ // @SystemApi(client= SystemApi.Client.MODULE_LIBRARIES) // TODO Uncomment once http://ag/9956147 is in.
+ public static int logToRadioBuffer(@Level int priority, @Nullable String tag,
+ @Nullable String message) {
+ return println_native(LOG_ID_RADIO, priority, tag, message);
+ }
+
+ /**
* Return the maximum payload the log daemon accepts without truncation.
* @return LOGGER_ENTRY_MAX_PAYLOAD.
*/
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 2223d14..fa994ba 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -25,6 +25,7 @@
import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.text.TextUtils;
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl
new file mode 100644
index 0000000..429c3ae
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowInsetsController.aidl
@@ -0,0 +1,48 @@
+/**
+ * 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.view;
+
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+/**
+ * Singular controller of insets to use when there isn't another obvious controller available.
+ * Specifically, this will take over insets control in multi-window.
+ * @hide
+ */
+oneway interface IDisplayWindowInsetsController {
+
+ /**
+ * @see IWindow#insetsChanged
+ */
+ void insetsChanged(in InsetsState insetsState);
+
+ /**
+ * @see IWindow#insetsControlChanged
+ */
+ void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+
+ /**
+ * @see IWindow#showInsets
+ */
+ void showInsets(int types, boolean fromIme);
+
+ /**
+ * @see IWindow#hideInsets
+ */
+ void hideInsets(int types, boolean fromIme);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9496827..993bdc4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,6 +35,7 @@
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowRotationController;
@@ -49,6 +50,7 @@
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
import android.view.InputEvent;
+import android.view.InsetsState;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.InputChannel;
@@ -711,4 +713,16 @@
* @return true if the display was successfully mirrored.
*/
boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl);
+
+ /**
+ * When in multi-window mode, the provided displayWindowInsetsController will control insets
+ * animations.
+ */
+ void setDisplayWindowInsetsController(
+ int displayId, in IDisplayWindowInsetsController displayWindowInsetsController);
+
+ /**
+ * Called when a remote process modifies insets on a display window container.
+ */
+ void modifyDisplayWindowInsets(int displayId, in InsetsState state);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index e3fed3a..ae1e579 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -19,10 +19,15 @@
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -156,11 +161,10 @@
&& source.getType() != ITYPE_IME;
boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
&& (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR);
- boolean skipIme = source.getType() == ITYPE_IME
- && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0;
boolean skipLegacyTypes = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && (toPublicType(type) & Type.compatSystemInsets()) != 0;
- if (skipSystemBars || skipIme || skipLegacyTypes || skipNonImeInImeMode) {
+ && (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR
+ || type == ITYPE_IME);
+ if (skipSystemBars || skipLegacyTypes || skipNonImeInImeMode) {
typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
continue;
}
@@ -175,8 +179,11 @@
typeMaxInsetsMap, null /* typeSideMap */, null /* typeVisibilityMap */);
}
}
+ final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout);
+ alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
+ ? systemBars() | ime()
+ : systemBars());
}
private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 52ea2b2..1782544 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -379,7 +379,7 @@
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
viewRoot.registerRtFrameCallback(frame -> {
try {
final SurfaceControl.Transaction t = useBLAST ?
@@ -1107,7 +1107,7 @@
private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
Rect position, long frameNumber) {
- if (frameNumber > 0 && ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (frameNumber > 0 && !WindowManagerGlobal.USE_BLAST_ADAPTER) {
final ViewRootImpl viewRoot = getViewRootImpl();
t.deferTransactionUntilSurface(surface, viewRoot.mSurface,
@@ -1125,7 +1125,7 @@
}
private void setParentSpaceRectangle(Rect position, long frameNumber) {
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
final ViewRootImpl viewRoot = getViewRootImpl();
final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
mRtTransaction;
@@ -1186,7 +1186,7 @@
@Override
public void positionLost(long frameNumber) {
- boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
@@ -1524,7 +1524,7 @@
@Override
public void invalidate(boolean invalidateCache) {
super.invalidate(invalidateCache);
- if (ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
return;
}
final ViewRootImpl viewRoot = getViewRootImpl();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 522ff9a..bf8dc65 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -192,11 +192,6 @@
private static final boolean MT_RENDERER_AVAILABLE = true;
/**
- * @hide
- */
- public static final boolean USE_BLAST_BUFFERQUEUE = false;
-
- /**
* If set to 2, the view system will switch from using rectangles retrieved from window to
* dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets
* directly from the full configuration, enabling richer information about the insets state, as
@@ -1312,7 +1307,7 @@
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
- if (USE_BLAST_BUFFERQUEUE) {
+ if (WindowManagerGlobal.USE_BLAST_ADAPTER) {
mWindowAttributes.privateFlags =
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
}
@@ -7273,7 +7268,7 @@
mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
if (mSurfaceControl.isValid()) {
- if (USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
mSurface.copyFrom(mSurfaceControl);
} else {
mSurface.transferFrom(getOrCreateBLASTSurface(
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index a9cc50f..9df131d 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -27,8 +27,8 @@
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
import static android.view.WindowInsets.Type.all;
-import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -87,6 +87,8 @@
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
+ private final int mCompatInsetTypes;
+
/**
* Since new insets may be added in the future that existing apps couldn't
* know about, this fully empty constant shouldn't be made available to apps
@@ -112,7 +114,7 @@
boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
- isRound, alwaysConsumeSystemBars, displayCutout);
+ isRound, alwaysConsumeSystemBars, displayCutout, systemBars());
}
/**
@@ -131,7 +133,7 @@
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
+ boolean alwaysConsumeSystemBars, DisplayCutout displayCutout, int compatInsetTypes) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -145,6 +147,7 @@
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
+ mCompatInsetTypes = compatInsetTypes;
mDisplayCutoutConsumed = displayCutout == null;
mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
@@ -160,7 +163,8 @@
this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
- src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
+ src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
+ src.mCompatInsetTypes);
}
private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
@@ -211,7 +215,8 @@
/** @hide */
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
- this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
+ this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
+ systemBars());
}
/**
@@ -280,7 +285,7 @@
*/
@NonNull
public Insets getSystemWindowInsets() {
- return getInsets(mTypeInsetsMap, compatSystemInsets());
+ return getInsets(mTypeInsetsMap, mCompatInsetTypes);
}
/**
@@ -439,7 +444,8 @@
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- null /* displayCutout */);
+ null /* displayCutout */,
+ mCompatInsetTypes);
}
@@ -485,7 +491,8 @@
return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
// TODO(b/119190588): replace @code with @link below
@@ -555,7 +562,7 @@
*/
@NonNull
public Insets getStableInsets() {
- return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
+ return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
}
/**
@@ -733,7 +740,8 @@
public WindowInsets consumeStableInsets() {
return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
/**
@@ -817,7 +825,8 @@
? null
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
- : mDisplayCutout.inset(left, top, right, bottom));
+ : mDisplayCutout.inset(left, top, right, bottom),
+ mCompatInsetTypes);
}
@Override
@@ -1134,7 +1143,8 @@
public WindowInsets build() {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
+ mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout,
+ systemBars());
}
}
@@ -1271,15 +1281,6 @@
}
/**
- * @return Inset types representing the list of bars that traditionally were denoted as
- * system insets.
- * @hide
- */
- static @InsetsType int compatSystemInsets() {
- return STATUS_BARS | NAVIGATION_BARS | IME;
- }
-
- /**
* @return All inset types combined.
*
* TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 9578002..7d5564e 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -57,6 +57,12 @@
private static final String TAG = "WindowManager";
/**
+ * This flag controls whether ViewRootImpl will utilize the Blast Adapter
+ * to send buffer updates to SurfaceFlinger
+ */
+ public static final boolean USE_BLAST_ADAPTER = false;
+
+ /**
* The user is navigating with keys (not the touch screen), so
* navigational focus should be shown.
*/
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
new file mode 100644
index 0000000..0b937fa
--- /dev/null
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -0,0 +1,34 @@
+/*
+ * 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.internal.compat;
+
+import android.os.Build;
+
+/**
+ * Platform private class for determining the type of Android build installed.
+ *
+ */
+public class AndroidBuildClassifier {
+
+ public boolean isDebuggableBuild() {
+ return Build.IS_DEBUGGABLE;
+ }
+
+ public boolean isFinalBuild() {
+ return "REL".equals(Build.VERSION.CODENAME);
+ }
+}
diff --git a/core/java/com/android/internal/compat/IOverrideValidator.aidl b/core/java/com/android/internal/compat/IOverrideValidator.aidl
new file mode 100644
index 0000000..add4708
--- /dev/null
+++ b/core/java/com/android/internal/compat/IOverrideValidator.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.internal.compat;
+
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Platform private API for determining whether a changeId can be overridden.
+ *
+ * {@hide}
+ */
+interface IOverrideValidator
+{
+ /**
+ * Validation function.
+ * @param changeId id of the change to be toggled on or off.
+ * @param packageName package of the app for which the change should be overridden.
+ * @return {@link OverrideAllowedState} specifying whether the change can be overridden for
+ * the given package or a reason why not.
+ */
+ OverrideAllowedState getOverrideAllowedState(long changeId, String packageName);
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 7dcb12c..4c203d3 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -17,6 +17,7 @@
package com.android.internal.compat;
import android.content.pm.ApplicationInfo;
+import com.android.internal.compat.IOverrideValidator;
import java.util.Map;
parcelable CompatibilityChangeConfig;
@@ -195,4 +196,9 @@
* @return An array of {@link CompatChangeInfo} known to the service.
*/
CompatibilityChangeInfo[] listAllChanges();
+
+ /**
+ * Get an instance that can determine whether a changeid can be overridden for a package name.
+ */
+ IOverrideValidator getOverrideValidator();
}
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.aidl b/core/java/com/android/internal/compat/OverrideAllowedState.aidl
new file mode 100644
index 0000000..10ceac7
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.compat;
+
+parcelable OverrideAllowedState;
\ No newline at end of file
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
new file mode 100644
index 0000000..56216c2
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -0,0 +1,153 @@
+/*
+ * 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.internal.compat;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class contains all the possible override allowed states.
+ */
+public final class OverrideAllowedState implements Parcelable {
+ @IntDef({
+ ALLOWED,
+ DISABLED_NOT_DEBUGGABLE,
+ DISABLED_NON_TARGET_SDK,
+ DISABLED_TARGET_SDK_TOO_HIGH,
+ PACKAGE_DOES_NOT_EXIST
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
+ /**
+ * Change can be overridden.
+ */
+ public static final int ALLOWED = 0;
+ /**
+ * Change cannot be overridden, due to the app not being debuggable.
+ */
+ public static final int DISABLED_NOT_DEBUGGABLE = 1;
+ /**
+ * Change cannot be overridden, due to the build being non-debuggable and the change being
+ * non-targetSdk.
+ */
+ public static final int DISABLED_NON_TARGET_SDK = 2;
+ /**
+ * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk.
+ */
+ public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3;
+ /**
+ * Package does not exist.
+ */
+ public static final int PACKAGE_DOES_NOT_EXIST = 4;
+
+ @State
+ public final int state;
+ public final int appTargetSdk;
+ public final int changeIdTargetSdk;
+
+ private OverrideAllowedState(Parcel parcel) {
+ state = parcel.readInt();
+ appTargetSdk = parcel.readInt();
+ changeIdTargetSdk = parcel.readInt();
+ }
+
+ public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) {
+ this.state = state;
+ this.appTargetSdk = appTargetSdk;
+ this.changeIdTargetSdk = changeIdTargetSdk;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(state);
+ out.writeInt(appTargetSdk);
+ out.writeInt(changeIdTargetSdk);
+ }
+
+ /**
+ * Enforces the policy for overriding compat changes.
+ *
+ * @param changeId the change id that was attempted to be overridden.
+ * @param packageName the package for which the attempt was made.
+ * @throws SecurityException if the policy forbids this operation.
+ */
+ public void enforce(long changeId, String packageName)
+ throws SecurityException {
+ switch (state) {
+ case ALLOWED:
+ return;
+ case DISABLED_NOT_DEBUGGABLE:
+ throw new SecurityException(
+ "Cannot override a change on a non-debuggable app and user build.");
+ case DISABLED_NON_TARGET_SDK:
+ throw new SecurityException(
+ "Cannot override a default enabled/disabled change on a user build.");
+ case DISABLED_TARGET_SDK_TOO_HIGH:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is "
+ + "above the change's targetSdk threshold (%4$d)",
+ changeId, packageName, appTargetSdk, changeIdTargetSdk));
+ case PACKAGE_DOES_NOT_EXIST:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the package does not exist, and "
+ + "the change is targetSdk gated.",
+ changeId, packageName));
+ }
+ }
+
+ public static final @NonNull
+ Parcelable.Creator<OverrideAllowedState> CREATOR =
+ new Parcelable.Creator<OverrideAllowedState>() {
+ public OverrideAllowedState createFromParcel(Parcel parcel) {
+ OverrideAllowedState info = new OverrideAllowedState(parcel);
+ return info;
+ }
+
+ public OverrideAllowedState[] newArray(int size) {
+ return new OverrideAllowedState[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof OverrideAllowedState)) {
+ return false;
+ }
+ OverrideAllowedState otherState = (OverrideAllowedState) obj;
+ return state == otherState.state
+ && appTargetSdk == otherState.appTargetSdk
+ && changeIdTargetSdk == otherState.changeIdTargetSdk;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl b/core/java/com/android/internal/telephony/IWapPushManager.aidl
similarity index 82%
rename from telephony/java/com/android/internal/telephony/IWapPushManager.aidl
rename to core/java/com/android/internal/telephony/IWapPushManager.aidl
index 1c3df65..9f6851b 100644
--- a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl
+++ b/core/java/com/android/internal/telephony/IWapPushManager.aidl
@@ -18,6 +18,7 @@
import android.content.Intent;
+/** @hide */
interface IWapPushManager {
/**
* Processes WAP push message and triggers the receiver application registered
@@ -26,11 +27,10 @@
int processMessage(String app_id, String content_type, in Intent intent);
/**
- * Add receiver application into the application ID table.
- * Returns true if inserting the information is successfull. Inserting the duplicated
+ * Adds receiver application into the application ID table.
+ * Returns true if inserting the information is successful. Inserting duplicated
* record in the application ID table is not allowed. Use update/delete method.
*/
- @UnsupportedAppUsage
boolean addPackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
@@ -39,17 +39,14 @@
* Updates receiver application that is last added.
* Returns true if updating the information is successfull.
*/
- @UnsupportedAppUsage
boolean updatePackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
/**
- * Delites receiver application information.
+ * Deletes receiver application information.
* Returns true if deleting is successfull.
*/
- @UnsupportedAppUsage
boolean deletePackage(String x_app_id, String content_type,
- String package_name, String class_name);
+ String package_name, String class_name);
}
-
diff --git a/core/java/com/android/internal/telephony/WapPushManagerParams.java b/core/java/com/android/internal/telephony/WapPushManagerParams.java
new file mode 100644
index 0000000..eafb8f1
--- /dev/null
+++ b/core/java/com/android/internal/telephony/WapPushManagerParams.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 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.internal.telephony;
+
+import android.telephony.WapPushManagerConnector;
+
+/**
+ * WapPushManager constant value definitions.
+ * @hide
+ */
+public class WapPushManagerParams {
+ /**
+ * Application type activity
+ */
+ public static final int APP_TYPE_ACTIVITY = 0;
+
+ /**
+ * Application type service
+ */
+ public static final int APP_TYPE_SERVICE = 1;
+
+ /**
+ * Process Message return value
+ * Message is handled
+ */
+ public static final int MESSAGE_HANDLED = WapPushManagerConnector.RESULT_MESSAGE_HANDLED;
+
+ /**
+ * Process Message return value
+ * Application ID or content type was not found in the application ID table
+ */
+ public static final int APP_QUERY_FAILED = WapPushManagerConnector.RESULT_APP_QUERY_FAILED;
+
+ /**
+ * Process Message return value
+ * Receiver application signature check failed
+ */
+ public static final int SIGNATURE_NO_MATCH = WapPushManagerConnector.RESULT_SIGNATURE_NO_MATCH;
+
+ /**
+ * Process Message return value
+ * Receiver application was not found
+ */
+ public static final int INVALID_RECEIVER_NAME =
+ WapPushManagerConnector.RESULT_INVALID_RECEIVER_NAME;
+
+ /**
+ * Process Message return value
+ * Unknown exception
+ */
+ public static final int EXCEPTION_CAUGHT = WapPushManagerConnector.RESULT_EXCEPTION_CAUGHT;
+
+ /**
+ * Process Message return value
+ * Need further processing after WapPushManager message processing
+ */
+ public static final int FURTHER_PROCESSING = WapPushManagerConnector.RESULT_FURTHER_PROCESSING;
+}
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
index 70627ed..c6925f4 100644
--- a/core/proto/android/server/animationadapter.proto
+++ b/core/proto/android/server/animationadapter.proto
@@ -50,6 +50,7 @@
optional WindowAnimationSpecProto window = 1;
optional MoveAnimationSpecProto move = 2;
optional AlphaAnimationSpecProto alpha = 3;
+ optional RotationAnimationSpecProto rotate = 4;
}
/* represents WindowAnimationSpec */
@@ -76,3 +77,12 @@
optional float to = 2;
optional int64 duration_ms = 3;
}
+
+/* represents RotationAnimationSpec */
+message RotationAnimationSpecProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional float start_luma = 1;
+ optional float end_luma = 2;
+ optional int64 duration_ms = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31faff6..ea70dcf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -456,7 +456,6 @@
<protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
<protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" />
- <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" />
<protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" />
<protected-broadcast android:name="android.intent.action.USER_UNLOCKED" />
diff --git a/core/res/res/anim/screen_rotate_0_enter.xml b/core/res/res/anim/screen_rotate_0_enter.xml
index 93cf365..629be7e 100644
--- a/core/res/res/anim/screen_rotate_0_enter.xml
+++ b/core/res/res/anim/screen_rotate_0_enter.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml
index 37d5a411..fa046a0 100644
--- a/core/res/res/anim/screen_rotate_0_exit.xml
+++ b/core/res/res/anim/screen_rotate_0_exit.xml
@@ -1,22 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_frame.xml b/core/res/res/anim/screen_rotate_0_frame.xml
deleted file mode 100644
index 5ea9bf8..0000000
--- a/core/res/res/anim/screen_rotate_0_frame.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
-</set>
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 688a8d5..889a615 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="180" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set>
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index 58a1868..766fcfa 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-180"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_alpha.xml b/core/res/res/anim/screen_rotate_alpha.xml
index c49ef9c..2cac982 100644
--- a/core/res/res/anim/screen_rotate_alpha.xml
+++ b/core/res/res/anim/screen_rotate_alpha.xml
@@ -20,8 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/decelerate_quint"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index b16d5fc..87fd25e 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -18,19 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase anim
+ android:shareInterpolator="false">
<rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index 0927dd3..c3aee14 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 86a8d24..8849db4 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -18,19 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index fd786f9..de84c3b 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_in.xml b/core/res/res/interpolator/screen_rotation_alpha_in.xml
new file mode 100644
index 0000000..9c566a7
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_in.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.15"
+ android:controlY1="0.45"
+ android:controlX2="0.33"
+ android:controlY2="1"/>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_out.xml b/core/res/res/interpolator/screen_rotation_alpha_out.xml
new file mode 100644
index 0000000..73a37d4
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_out.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.57"
+ android:controlY1="0"
+ android:controlX2="0.71"
+ android:controlY2=".43"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6691d4c..245aed1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -147,6 +147,24 @@
<integer name="config_activityShortDur">150</integer>
<integer name="config_activityDefaultDur">220</integer>
+ <!-- Fade out time for screen rotation -->
+ <integer name="config_screen_rotation_fade_out">116</integer>
+
+ <!-- Fade in time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in">233</integer>
+
+ <!-- Fade in delay time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in_delay">100</integer>
+
+ <!-- Total time for 90 degree screen rotation animations -->
+ <integer name="config_screen_rotation_total_90">333</integer>
+
+ <!-- Total time for 180 degree screen rotation animation -->
+ <integer name="config_screen_rotation_total_180">433</integer>
+
+ <!-- Total time for the rotation background color transition -->
+ <integer name="config_screen_rotation_color_transition">200</integer>
+
<!-- The duration (in milliseconds) of the tooltip show/hide animations. -->
<integer name="config_tooltipAnimTime">150</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01bd510..cdbf14b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1805,7 +1805,6 @@
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
<java-symbol type="anim" name="screen_rotate_0_exit" />
- <java-symbol type="anim" name="screen_rotate_0_frame" />
<java-symbol type="anim" name="screen_rotate_180_enter" />
<java-symbol type="anim" name="screen_rotate_180_exit" />
<java-symbol type="anim" name="screen_rotate_180_frame" />
@@ -1981,6 +1980,7 @@
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
<java-symbol type="integer" name="config_brightness_ramp_rate_slow" />
+ <java-symbol type="integer" name="config_screen_rotation_color_transition" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index de6f8f7..750ffa1 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
index 9b3d0c9..b88c36f 100644
--- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index bee270e..ba29a97 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/os/TimestampedValueTest.java
similarity index 98%
rename from core/tests/coretests/src/android/util/TimestampedValueTest.java
rename to core/tests/coretests/src/android/os/TimestampedValueTest.java
index 6fc2400..f36d9e6 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/os/TimestampedValueTest.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
-import android.os.Parcel;
-
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 6062088..fa2ffcca 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -23,6 +23,7 @@
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.junit.Assert.assertEquals;
@@ -116,14 +117,18 @@
@Test
public void testCalculateInsets_imeIgnoredWithoutAdjustResize() {
- mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
- mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
- mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
- mState.getSource(ITYPE_IME).setVisible(true);
- WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
- DisplayCutout.NO_CUTOUT, null, null, 0, null);
- assertEquals(0, insets.getSystemWindowInsetBottom());
- assertTrue(insets.isVisible(ime()));
+ try (final InsetsModeSession session =
+ new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+ DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_NOTHING, null);
+ assertEquals(0, insets.getSystemWindowInsetBottom());
+ assertEquals(100, insets.getInsets(ime()).bottom);
+ assertTrue(insets.isVisible(ime()));
+ }
}
@Test
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 8c7b28a..e5a4f6d 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -63,7 +63,8 @@
b.setInsets(navigationBars(), Insets.of(0, 0, 0, 100));
b.setInsets(ime(), Insets.of(0, 0, 0, 300));
WindowInsets insets = b.build();
- assertEquals(300, insets.getSystemWindowInsets().bottom);
+ assertEquals(100, insets.getSystemWindowInsets().bottom);
+ assertEquals(300, insets.getInsets(ime()).bottom);
}
// TODO: Move this to CTS once API made public
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index e53f3db..6d4a0c6 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -52,8 +52,8 @@
DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
}
-void DeviceInfo::onDisplayConfigChanged() {
- updateDisplayInfo();
+void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) {
+ mVsyncPeriod = vsyncPeriod;
}
void DeviceInfo::updateDisplayInfo() {
@@ -113,10 +113,11 @@
ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex];
status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status);
+
mWidth = ADisplayConfig_getWidth(mCurrentConfig);
mHeight = ADisplayConfig_getHeight(mCurrentConfig);
mDensity = ADisplayConfig_getDensity(mCurrentConfig);
- mRefreshRate = ADisplayConfig_getFps(mCurrentConfig);
+ mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig));
mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig);
mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig);
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index a420746..16a22f4 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -37,7 +37,7 @@
static int32_t getWidth() { return get()->mWidth; }
static int32_t getHeight() { return get()->mHeight; }
static float getDensity() { return get()->mDensity; }
- static float getRefreshRate() { return get()->mRefreshRate; }
+ static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; }
static int64_t getCompositorOffset() { return get()->mCompositorOffset; }
static int64_t getAppOffset() { return get()->mAppOffset; }
@@ -47,7 +47,8 @@
sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
SkColorType getWideColorType() const { return mWideColorType; }
- void onDisplayConfigChanged();
+ // This method should be called whenever the display refresh rate changes.
+ void onRefreshRateChanged(int64_t vsyncPeriod);
private:
friend class renderthread::RenderThread;
@@ -68,7 +69,7 @@
int32_t mWidth = 1080;
int32_t mHeight = 1920;
float mDensity = 2.0;
- float mRefreshRate = 60.0;
+ int64_t mVsyncPeriod = 16666666;
int64_t mCompositorOffset = 0;
int64_t mAppOffset = 0;
};
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 10e7160..d25fc4b 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -81,7 +81,7 @@
JankTracker::JankTracker(ProfileDataContainer* globalData) {
mGlobalData = globalData;
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
nsecs_t sfOffset = DeviceInfo::getCompositorOffset();
nsecs_t offsetDelta = sfOffset - DeviceInfo::getAppOffset();
// There are two different offset cases. If the offsetDelta is positive
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a446858..d78f641 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -34,7 +34,6 @@
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>
-#include <gui/DisplayEventReceiver.h>
#include <sys/resource.h>
#include <utils/Condition.h>
#include <utils/Log.h>
@@ -45,53 +44,43 @@
namespace uirenderer {
namespace renderthread {
-// Number of events to read at a time from the DisplayEventReceiver pipe.
-// The value should be large enough that we can quickly drain the pipe
-// using just a few large reads.
-static const size_t EVENT_BUFFER_SIZE = 100;
-
static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
-class DisplayEventReceiverWrapper : public VsyncSource {
+void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ rt->mVsyncRequested = false;
+ if (rt->timeLord().vsyncReceived(frameTimeNanos) && !rt->mFrameCallbackTaskPending) {
+ ATRACE_NAME("queue mFrameCallbackTask");
+ rt->mFrameCallbackTaskPending = true;
+ nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
+ rt->queue().postAt(runAt, [=]() { rt->dispatchFrameCallbacks(); });
+ }
+}
+
+void RenderThread::refreshRateCallback(int64_t vsyncPeriod, void* data) {
+ ATRACE_NAME("refreshRateCallback");
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ DeviceInfo::get()->onRefreshRateChanged(vsyncPeriod);
+ rt->setupFrameInterval();
+}
+
+class ChoreographerSource : public VsyncSource {
public:
- DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver,
- const std::function<void()>& onDisplayConfigChanged)
- : mDisplayEventReceiver(std::move(receiver))
- , mOnDisplayConfigChanged(onDisplayConfigChanged) {}
+ ChoreographerSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- status_t status = mDisplayEventReceiver->requestNextVsync();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
+ AChoreographer_postFrameCallback64(mRenderThread->mChoreographer,
+ RenderThread::frameCallback, mRenderThread);
}
- virtual nsecs_t latestVsyncEvent() override {
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- nsecs_t latest = 0;
- ssize_t n;
- while ((n = mDisplayEventReceiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (ssize_t i = 0; i < n; i++) {
- const DisplayEventReceiver::Event& ev = buf[i];
- switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- latest = ev.header.timestamp;
- break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- mOnDisplayConfigChanged();
- break;
- }
- }
- }
- if (n < 0) {
- ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
- }
- return latest;
+ virtual void drainPendingEvents() override {
+ AChoreographer_handlePendingEvents(mRenderThread->mChoreographer, mRenderThread);
}
private:
- std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
- std::function<void()> mOnDisplayConfigChanged;
+ RenderThread* mRenderThread;
};
class DummyVsyncSource : public VsyncSource {
@@ -99,11 +88,14 @@
DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- mRenderThread->queue().postDelayed(16_ms,
- [this]() { mRenderThread->drainDisplayEventQueue(); });
+ mRenderThread->queue().postDelayed(16_ms, [this]() {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ });
}
- virtual nsecs_t latestVsyncEvent() override { return systemTime(SYSTEM_TIME_MONOTONIC); }
+ virtual void drainPendingEvents() override {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ }
private:
RenderThread* mRenderThread;
@@ -145,29 +137,24 @@
}
RenderThread::~RenderThread() {
+ // Note that if this fatal assertion is removed then member variables must
+ // be properly destroyed.
LOG_ALWAYS_FATAL("Can't destroy the render thread");
}
-void RenderThread::initializeDisplayEventReceiver() {
- LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second DisplayEventReceiver?");
+void RenderThread::initializeChoreographer() {
+ LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second Choreographer?");
if (!Properties::isolatedProcess) {
- auto receiver = std::make_unique<DisplayEventReceiver>(
- ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::eConfigChangedDispatch);
- status_t status = receiver->initCheck();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "Initialization of DisplayEventReceiver "
- "failed with status: %d",
- status);
+ mChoreographer = AChoreographer_create();
+ LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
+ AChoreographer_registerRefreshRateCallback(mChoreographer,
+ RenderThread::refreshRateCallback, this);
// Register the FD
- mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
- RenderThread::displayEventReceiverCallback, this);
- mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
- DeviceInfo::get()->onDisplayConfigChanged();
- setupFrameInterval();
- });
+ mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
+ RenderThread::choreographerCallback, this);
+ mVsyncSource = new ChoreographerSource(this);
} else {
mVsyncSource = new DummyVsyncSource(this);
}
@@ -175,7 +162,7 @@
void RenderThread::initThreadLocals() {
setupFrameInterval();
- initializeDisplayEventReceiver();
+ initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager();
@@ -183,7 +170,7 @@
}
void RenderThread::setupFrameInterval() {
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
mTimeLord.setFrameInterval(frameIntervalNanos);
mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
}
@@ -288,7 +275,7 @@
}
}
-int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
+int RenderThread::choreographerCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x",
@@ -302,24 +289,10 @@
events);
return 1; // keep the callback
}
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ AChoreographer_handlePendingEvents(rt->mChoreographer, data);
- reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
-
- return 1; // keep the callback
-}
-
-void RenderThread::drainDisplayEventQueue() {
- ATRACE_CALL();
- nsecs_t vsyncEvent = mVsyncSource->latestVsyncEvent();
- if (vsyncEvent > 0) {
- mVsyncRequested = false;
- if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
- ATRACE_NAME("queue mFrameCallbackTask");
- mFrameCallbackTaskPending = true;
- nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay);
- queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
- }
- }
+ return 1;
}
void RenderThread::dispatchFrameCallbacks() {
@@ -360,7 +333,7 @@
processQueue();
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
- drainDisplayEventQueue();
+ mVsyncSource->drainPendingEvents();
mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index da79e97..8be46a6 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,6 +19,7 @@
#include <GrContext.h>
#include <SkBitmap.h>
+#include <apex/choreographer.h>
#include <cutils/compiler.h>
#include <thread/ThreadBase.h>
#include <utils/Looper.h>
@@ -73,10 +74,11 @@
struct VsyncSource {
virtual void requestNextVsync() = 0;
- virtual nsecs_t latestVsyncEvent() = 0;
+ virtual void drainPendingEvents() = 0;
virtual ~VsyncSource() {}
};
+class ChoreographerSource;
class DummyVsyncSource;
typedef void (*JVMAttachHook)(const char* name);
@@ -136,6 +138,7 @@
friend class DispatchFrameCallbacks;
friend class RenderProxy;
friend class DummyVsyncSource;
+ friend class ChoreographerSource;
friend class android::uirenderer::AutoBackendTextureRelease;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
@@ -149,13 +152,21 @@
static RenderThread& getInstance();
void initThreadLocals();
- void initializeDisplayEventReceiver();
+ void initializeChoreographer();
void setupFrameInterval();
- static int displayEventReceiverCallback(int fd, int events, void* data);
+ // Callbacks for choreographer events:
+ // choreographerCallback will call AChoreograper_handleEvent to call the
+ // corresponding callbacks for each display event type
+ static int choreographerCallback(int fd, int events, void* data);
+ // Callback that will be run on vsync ticks.
+ static void frameCallback(int64_t frameTimeNanos, void* data);
+ // Callback that will be run whenver there is a refresh rate change.
+ static void refreshRateCallback(int64_t vsyncPeriod, void* data);
void drainDisplayEventQueue();
void dispatchFrameCallbacks();
void requestVsync();
+ AChoreographer* mChoreographer;
VsyncSource* mVsyncSource;
bool mVsyncRequested;
std::set<IFrameCallback*> mFrameCallbacks;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 7fca03c..4cd581b 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -354,8 +355,8 @@
* is less than or equal to 0.
* @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
*/
- public @Nullable Bitmap getScaledFrameAtTime(
- long timeUs, @Option int option, int dstWidth, int dstHeight) {
+ public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
}
@@ -400,7 +401,8 @@
* @see {@link #getScaledFrameAtTime(long, int, int, int)}
*/
public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
- int dstWidth, int dstHeight, @NonNull BitmapParams params) {
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight,
+ @NonNull BitmapParams params) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
}
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index ab7bbca..c17beba 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -62,6 +62,7 @@
private final int mAudioChannelCount;
private final int mAudioSampleRate;
private final boolean mAudioDescription;
+ private final boolean mHardOfHearing;
private final int mVideoWidth;
private final int mVideoHeight;
private final float mVideoFrameRate;
@@ -72,8 +73,8 @@
private TvTrackInfo(int type, String id, String language, CharSequence description,
boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription,
- int videoWidth, int videoHeight, float videoFrameRate, float videoPixelAspectRatio,
- byte videoActiveFormatDescription, Bundle extra) {
+ boolean hardOfHearing, int videoWidth, int videoHeight, float videoFrameRate,
+ float videoPixelAspectRatio, byte videoActiveFormatDescription, Bundle extra) {
mType = type;
mId = id;
mLanguage = language;
@@ -82,6 +83,7 @@
mAudioChannelCount = audioChannelCount;
mAudioSampleRate = audioSampleRate;
mAudioDescription = audioDescription;
+ mHardOfHearing = hardOfHearing;
mVideoWidth = videoWidth;
mVideoHeight = videoHeight;
mVideoFrameRate = videoFrameRate;
@@ -99,6 +101,7 @@
mAudioChannelCount = in.readInt();
mAudioSampleRate = in.readInt();
mAudioDescription = in.readInt() != 0;
+ mHardOfHearing = in.readInt() != 0;
mVideoWidth = in.readInt();
mVideoHeight = in.readInt();
mVideoFrameRate = in.readFloat();
@@ -192,6 +195,23 @@
}
/**
+ * Returns {@code true} if the track is intended for people with hearing impairment, {@code
+ * false} otherwise. Valid only for {@link #TYPE_AUDIO} and {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language
+ * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468).
+ *
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ public boolean isHardOfHearing() {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio or a subtitle track");
+ }
+ return mHardOfHearing;
+ }
+
+ /**
* Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -287,6 +307,7 @@
dest.writeInt(mAudioChannelCount);
dest.writeInt(mAudioSampleRate);
dest.writeInt(mAudioDescription ? 1 : 0);
+ dest.writeInt(mHardOfHearing ? 1 : 0);
dest.writeInt(mVideoWidth);
dest.writeInt(mVideoHeight);
dest.writeFloat(mVideoFrameRate);
@@ -318,7 +339,8 @@
case TYPE_AUDIO:
return mAudioChannelCount == obj.mAudioChannelCount
&& mAudioSampleRate == obj.mAudioSampleRate
- && mAudioDescription == obj.mAudioDescription;
+ && mAudioDescription == obj.mAudioDescription
+ && mHardOfHearing == obj.mHardOfHearing;
case TYPE_VIDEO:
return mVideoWidth == obj.mVideoWidth
@@ -326,6 +348,9 @@
&& mVideoFrameRate == obj.mVideoFrameRate
&& mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio
&& mVideoActiveFormatDescription == obj.mVideoActiveFormatDescription;
+
+ case TYPE_SUBTITLE:
+ return mHardOfHearing == obj.mHardOfHearing;
}
return true;
@@ -361,6 +386,7 @@
private int mAudioChannelCount;
private int mAudioSampleRate;
private boolean mAudioDescription;
+ private boolean mHardOfHearing;
private int mVideoWidth;
private int mVideoHeight;
private float mVideoFrameRate;
@@ -474,6 +500,27 @@
}
/**
+ * Sets the hard of hearing attribute of the track. Valid only for {@link #TYPE_AUDIO} and
+ * {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio
+ * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN
+ * 300 468).
+ *
+ * @param hardOfHearing The hard of hearing attribute of the track.
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ @NonNull
+ public Builder setHardOfHearing(boolean hardOfHearing) {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio track or a subtitle track");
+ }
+ mHardOfHearing = hardOfHearing;
+ return this;
+ }
+
+ /**
* Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -575,8 +622,8 @@
*/
public TvTrackInfo build() {
return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted,
- mAudioChannelCount, mAudioSampleRate, mAudioDescription, mVideoWidth,
- mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio,
+ mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing,
+ mVideoWidth, mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio,
mVideoActiveFormatDescription, mExtra);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3c3ebe2..1ee8518 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -110,6 +110,7 @@
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
@@ -276,6 +277,7 @@
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -363,6 +365,7 @@
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index a1eccce..7108e65 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -70,6 +70,7 @@
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -146,6 +147,7 @@
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -232,6 +234,7 @@
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index f0ac08b..982aa8e 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -18,7 +18,10 @@
<com.android.systemui.statusbar.notification.stack.PeopleHubView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="105dp">
+ android:layout_height="@dimen/notification_section_header_height"
+ android:focusable="true"
+ android:clickable="true"
+>
<com.android.systemui.statusbar.notification.row.NotificationBackgroundView
android:id="@+id/backgroundNormal"
@@ -34,199 +37,56 @@
android:id="@+id/people_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
android:gravity="center"
android:orientation="horizontal">
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginStart="@dimen/notification_section_header_padding_left"
+ android:gravity="start"
+ android:textAlignment="gravity"
+ android:text="@string/notification_section_header_conversations"
+ android:textSize="12sp"
+ android:textColor="@color/notification_section_header_label_color"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
</LinearLayout>
@@ -236,4 +96,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-</com.android.systemui.statusbar.notification.stack.PeopleHubView>
\ No newline at end of file
+</com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 52c0a26..4f532b7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1163,6 +1163,9 @@
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
+ <!-- Section title for conversational notifications. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_conversations">Conversations</string>
+
<!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
<string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string>
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index eecc54c..bbe972d 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -121,6 +121,7 @@
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.wm.DisplayImeController;
import com.android.systemui.wm.DisplayWindowController;
import com.android.systemui.wm.SystemWindows;
@@ -321,6 +322,7 @@
@Inject Lazy<StatusBar> mStatusBar;
@Inject Lazy<DisplayWindowController> mDisplayWindowController;
@Inject Lazy<SystemWindows> mSystemWindows;
+ @Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject
public Dependency() {
@@ -509,6 +511,7 @@
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
mProviders.put(SystemWindows.class, mSystemWindows::get);
+ mProviders.put(DisplayImeController.class, mDisplayImeController::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7cd29ea..c7492a2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -344,11 +344,14 @@
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mCurrentUserId = mNotifUserManager.getCurrentUserId();
mNotifUserManager.addUserChangedListener(
- newUserId -> {
- saveBubbles(mCurrentUserId);
- mBubbleData.dismissAll(DISMISS_USER_CHANGED);
- restoreBubbles(newUserId);
- mCurrentUserId = newUserId;
+ new NotificationLockscreenUserManager.UserChangedListener() {
+ @Override
+ public void onUserChanged(int newUserId) {
+ BubbleController.this.saveBubbles(mCurrentUserId);
+ mBubbleData.dismissAll(DISMISS_USER_CHANGED);
+ BubbleController.this.restoreBubbles(newUserId);
+ mCurrentUserId = newUserId;
+ }
});
mUserCreatedBubbles = new HashSet<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index ff4ce94..ebf7c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -49,6 +49,12 @@
/** Adds a listener to be notified when the current user changes. */
void addUserChangedListener(UserChangedListener listener);
+ /**
+ * Removes a listener previously registered with
+ * {@link #addUserChangedListener(UserChangedListener)}
+ */
+ void removeUserChangedListener(UserChangedListener listener);
+
SparseArray<UserInfo> getCurrentProfiles();
void setLockscreenPublicMode(boolean isProfilePublic, int userId);
@@ -79,6 +85,7 @@
/** Notified when the current user changes. */
interface UserChangedListener {
- void onUserChanged(int userId);
+ default void onUserChanged(int userId) {}
+ default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2e369b3..976531d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -117,51 +117,63 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ mCurrentUserId = intent.getIntExtra(
+ Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ updateCurrentProfilesCache();
- updateLockscreenNotificationSetting();
- updatePublicMode();
- // The filtering needs to happen before the update call below in order to make sure
- // the presenter has the updated notifications from the new user
- getEntryManager().reapplyFilterAndSort("user switched");
- mPresenter.onUserSwitched(mCurrentUserId);
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
- for (UserChangedListener listener : mListeners) {
- listener.onUserChanged(mCurrentUserId);
- }
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- // Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
+ updateLockscreenNotificationSetting();
+ updatePublicMode();
+ // The filtering needs to happen before the update call below in order to
+ // make sure
+ // the presenter has the updated notifications from the new user
+ getEntryManager().reapplyFilterAndSort("user switched");
+ mPresenter.onUserSwitched(mCurrentUserId);
+
+ for (UserChangedListener listener : mListeners) {
+ listener.onUserChanged(mCurrentUserId);
}
- }
- if (notificationKey != null) {
- NotificationEntry entry =
- getEntryManager().getActiveNotificationUnfiltered(notificationKey);
- final int count = getEntryManager().getActiveNotificationsCount();
- final int rank = entry != null ? entry.getRanking().getRank() : 0;
- NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(entry);
- final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
- rank, count, true, location);
- try {
- mBarService.onNotificationClick(notificationKey, nv);
- } catch (RemoteException exception) {
- /* ignore */
+ break;
+ case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
+ case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
+ updateCurrentProfilesCache();
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ break;
+ case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
+ final IntentSender intentSender = intent.getParcelableExtra(
+ Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
}
- }
+ if (notificationKey != null) {
+ NotificationEntry entry =
+ getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+ final int count = getEntryManager().getActiveNotificationsCount();
+ final int rank = entry != null ? entry.getRanking().getRank() : 0;
+ NotificationVisibility.NotificationLocation location =
+ NotificationLogger.getNotificationLocation(entry);
+ final NotificationVisibility nv = NotificationVisibility.obtain(
+ notificationKey,
+ rank, count, true, location);
+ try {
+ mBarService.onNotificationClick(notificationKey, nv);
+ } catch (RemoteException exception) {
+ /* ignore */
+ }
+ }
+ break;
}
}
};
@@ -266,6 +278,8 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter);
IntentFilter internalFilter = new IntentFilter();
@@ -489,6 +503,11 @@
}
}
}
+ mMainHandler.post(() -> {
+ for (UserChangedListener listener : mListeners) {
+ listener.onCurrentProfilesChanged(mCurrentProfiles);
+ }
+ });
}
public boolean isAnyProfilePublicMode() {
@@ -555,6 +574,11 @@
mListeners.add(listener);
}
+ @Override
+ public void removeUserChangedListener(UserChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
// public void updatePublicMode() {
// //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
// // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 43d0399..667e721 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -584,7 +584,15 @@
public void bindRow(ExpandableNotificationRow row) {
row.setRemoteInputController(mRemoteInputController);
- row.setRemoteViewClickHandler(mOnClickHandler);
+ }
+
+ /**
+ * Return on-click handler for notification remote views
+ *
+ * @return on-click handler
+ */
+ public RemoteViews.OnClickHandler getRemoteViewsOnClickHandler() {
+ return mOnClickHandler;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
index d1f6ebf..ec8dbea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.systemui.statusbar.notification.row.NotificationRowModule;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -26,7 +28,7 @@
/**
* Dagger Module providing common dependencies of StatusBar.
*/
-@Module
+@Module(includes = {NotificationRowModule.class})
public class StatusBarDependenciesModule {
/**
* Provides our instance of CommandQueue which is considered optional.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 873cdbc..856b75b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -299,6 +299,14 @@
if (!isLifetimeExtended(entry)) {
Ranking ranking = requireRanking(rankingMap, entry.getKey());
entry.setRanking(ranking);
+
+ // TODO: (b/145659174) update the sbn's overrideGroupKey in
+ // NotificationEntry.setRanking instead of here once we fully migrate to the
+ // NewNotifPipeline
+ final String newOverrideGroupKey = ranking.getOverrideGroupKey();
+ if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), newOverrideGroupKey)) {
+ entry.getSbn().setOverrideGroupKey(newOverrideGroupKey);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 6dc647d..20f206b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -41,8 +41,8 @@
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -65,6 +65,7 @@
Dependency.get(NotificationInterruptionStateProvider.class);
private final Context mContext;
+ private final NotificationRowContentBinder mRowContentBinder;
private final NotificationMessagingUtil mMessagingUtil;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -76,7 +77,7 @@
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
private HeadsUpManager mHeadsUpManager;
- private NotificationContentInflater.InflationCallback mInflationCallback;
+ private NotificationRowContentBinder.InflationCallback mInflationCallback;
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
@@ -84,11 +85,13 @@
public NotificationRowBinderImpl(
Context context,
+ NotificationRowContentBinder rowContentBinder,
boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
StatusBarStateController statusBarStateController,
NotificationLogger logger) {
mContext = context;
+ mRowContentBinder = rowContentBinder;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
@@ -117,7 +120,7 @@
mOnAppOpsClickListener = mGutsManager::openGuts;
}
- public void setInflationCallback(NotificationContentInflater.InflationCallback callback) {
+ public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) {
mInflationCallback = callback;
}
@@ -156,19 +159,6 @@
private void bindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row,
Runnable onDismissRunnable) {
- row.setExpansionLogger(mExpansionLogger, entry.getSbn().getKey());
- row.setBypassController(mKeyguardBypassController);
- row.setStatusBarStateController(mStatusBarStateController);
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setOnExpandClickListener(mPresenter);
- row.setInflationCallback(mInflationCallback);
- if (mAllowLongPress) {
- row.setLongPressListener(mGutsManager::openGuts);
- }
- mListContainer.bindRow(row);
- getRemoteInputManager().bindRow(row);
-
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
// but since this field is used in the guts, it must be accurate.
@@ -186,15 +176,33 @@
} catch (PackageManager.NameNotFoundException e) {
// Do nothing
}
- row.setAppName(appname);
+
+ row.initialize(
+ appname,
+ sbn.getKey(),
+ mExpansionLogger,
+ mKeyguardBypassController,
+ mGroupManager,
+ mHeadsUpManager,
+ mRowContentBinder,
+ mPresenter);
+
+ // TODO: Either move these into ExpandableNotificationRow#initialize or out of row entirely
+ row.setStatusBarStateController(mStatusBarStateController);
+ row.setInflationCallback(mInflationCallback);
+ row.setAppOpsOnClickListener(mOnAppOpsClickListener);
+ if (mAllowLongPress) {
+ row.setLongPressListener(mGutsManager::openGuts);
+ }
+ mListContainer.bindRow(row);
+ getRemoteInputManager().bindRow(row);
+
row.setOnDismissRunnable(onDismissRunnable);
row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (ENABLE_REMOTE_INPUT) {
row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
- row.setAppOpsOnClickListener(mOnAppOpsClickListener);
-
mBindRowCallback.onBindRow(entry, pmUser, sbn, row);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
index 2c0c942..e81d361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
@@ -37,7 +37,8 @@
val key: PersonKey,
val name: CharSequence,
val avatar: Drawable,
- val clickIntent: PendingIntent
+ val clickIntent: PendingIntent,
+ val userId: Int
)
/** Unique identifier for a Person in PeopleHub. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 784673e..88b4147 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -17,28 +17,27 @@
package com.android.systemui.statusbar.notification.people
import android.app.Notification
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.ColorFilter
-import android.graphics.PixelFormat
-import android.graphics.drawable.BitmapDrawable
+import android.content.pm.UserInfo
import android.graphics.drawable.Drawable
-import android.os.UserHandle
+import android.os.UserManager
import android.service.notification.StatusBarNotification
-import android.util.TypedValue
+import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.android.internal.statusbar.NotificationVisibility
import com.android.internal.widget.MessagingGroup
-import com.android.launcher3.icons.BaseIconFactory
import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.NotificationPersonExtractorPlugin
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.NotificationEntryListener
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.policy.ExtensionController
import java.util.ArrayDeque
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
@@ -52,8 +51,7 @@
@Singleton
class NotificationPersonExtractorPluginBoundary @Inject constructor(
- extensionController: ExtensionController,
- private val context: Context
+ extensionController: ExtensionController
) : NotificationPersonExtractor {
private var plugin: NotificationPersonExtractorPlugin? = null
@@ -70,9 +68,8 @@
}
override fun extractPerson(sbn: StatusBarNotification) =
- plugin?.extractPerson(sbn)?.let { data ->
- val badged = addBadgeToDrawable(data.avatar, context, sbn.packageName, sbn.user)
- PersonModel(data.key, data.name, badged, data.clickIntent)
+ plugin?.extractPerson(sbn)?.run {
+ PersonModel(key, name, avatar, clickIntent, sbn.user.identifier)
}
override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
@@ -84,11 +81,16 @@
@Singleton
class PeopleHubDataSourceImpl @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
- private val peopleHubManager: PeopleHubManager,
- private val extractor: NotificationPersonExtractor
+ private val extractor: NotificationPersonExtractor,
+ private val userManager: UserManager,
+ @Background private val bgExecutor: Executor,
+ @Main private val mainExecutor: Executor,
+ private val notifLockscreenUserMgr: NotificationLockscreenUserManager
) : DataSource<PeopleHubModel> {
+ private var userChangeSubscription: Subscription? = null
private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
+ private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
private val notificationEntryListener = object : NotificationEntryListener {
override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
@@ -106,31 +108,56 @@
}
private fun removeVisibleEntry(entry: NotificationEntry) {
- val key = extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey()
- if (key?.let(peopleHubManager::removeActivePerson) == true) {
- updateUi()
+ (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) {
+ updateUi()
+ }
+ }
+ }
}
}
private fun addVisibleEntry(entry: NotificationEntry) {
- val personModel = extractor.extractPerson(entry.sbn) ?: entry.extractPerson()
- if (personModel?.let(peopleHubManager::addActivePerson) == true) {
- updateUi()
+ (extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ val manager = peopleHubManagerForUser[parentId]
+ ?: PeopleHubManager().also { peopleHubManagerForUser.put(parentId, it) }
+ if (manager.addActivePerson(personModel)) {
+ updateUi()
+ }
+ }
+ }
}
}
override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
- val registerWithNotificationEntryManager = dataListeners.isEmpty()
+ val register = dataListeners.isEmpty()
dataListeners.add(listener)
- if (registerWithNotificationEntryManager) {
+ if (register) {
+ userChangeSubscription = notifLockscreenUserMgr.registerListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) = updateUi()
+ override fun onCurrentProfilesChanged(
+ currentProfiles: SparseArray<UserInfo>?
+ ) = updateUi()
+ })
notificationEntryManager.addNotificationEntryListener(notificationEntryListener)
} else {
- listener.onDataChanged(peopleHubManager.getPeopleHubModel())
+ getPeopleHubModelForCurrentUser()?.let(listener::onDataChanged)
}
return object : Subscription {
override fun unsubscribe() {
dataListeners.remove(listener)
if (dataListeners.isEmpty()) {
+ userChangeSubscription?.unsubscribe()
+ userChangeSubscription = null
notificationEntryManager
.removeNotificationEntryListener(notificationEntryListener)
}
@@ -138,16 +165,36 @@
}
}
+ private fun getPeopleHubModelForCurrentUser(): PeopleHubModel? {
+ val currentUserId = notifLockscreenUserMgr.currentUserId
+ val model = peopleHubManagerForUser[currentUserId]?.getPeopleHubModel()
+ ?: return null
+ val currentProfiles = notifLockscreenUserMgr.currentProfiles
+ return model.copy(people = model.people.filter { person ->
+ currentProfiles[person.userId]?.isQuietModeEnabled == false
+ })
+ }
+
private fun updateUi() {
- val model = peopleHubManager.getPeopleHubModel()
+ val model = getPeopleHubModelForCurrentUser() ?: return
for (listener in dataListeners) {
listener.onDataChanged(model)
}
}
}
-@Singleton
-class PeopleHubManager @Inject constructor() {
+private fun NotificationLockscreenUserManager.registerListener(
+ listener: NotificationLockscreenUserManager.UserChangedListener
+): Subscription {
+ addUserChangedListener(listener)
+ return object : Subscription {
+ override fun unsubscribe() {
+ removeUserChangedListener(listener)
+ }
+ }
+}
+
+class PeopleHubManager {
private val activePeople = mutableMapOf<PersonKey, PersonModel>()
private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
@@ -157,7 +204,7 @@
if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) {
inactivePeople.removeLast()
}
- inactivePeople.push(data)
+ inactivePeople.add(data)
return true
}
return false
@@ -190,63 +237,7 @@
?: extras.getString(Notification.EXTRA_TITLE)
?: return null
val drawable = extractAvatarFromRow(this) ?: return null
- val badgedAvatar = addBadgeToDrawable(drawable, row.context, sbn.packageName, sbn.user)
- return PersonModel(key, name, badgedAvatar, clickIntent)
-}
-
-private fun addBadgeToDrawable(
- drawable: Drawable,
- context: Context,
- packageName: String,
- user: UserHandle
-): Drawable {
- val pm = context.packageManager
- val appInfo = pm.getApplicationInfoAsUser(packageName, 0, user)
- return object : Drawable() {
- override fun draw(canvas: Canvas) {
- val iconBounds = getBounds()
- val factory = object : BaseIconFactory(
- context,
- 0 /* unused */,
- iconBounds.width(),
- true) {}
- val badge = factory.createBadgedIconBitmap(
- appInfo.loadIcon(pm),
- user,
- true,
- appInfo.isInstantApp,
- null)
- val badgeDrawable = BitmapDrawable(context.resources, badge.icon)
- .apply {
- alpha = drawable.alpha
- colorFilter = drawable.colorFilter
- val badgeWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 15f,
- context.resources.displayMetrics
- ).toInt()
- setBounds(
- iconBounds.left + (iconBounds.width() - badgeWidth),
- iconBounds.top + (iconBounds.height() - badgeWidth),
- iconBounds.right,
- iconBounds.bottom)
- }
- drawable.bounds = iconBounds
- drawable.draw(canvas)
- badgeDrawable.draw(canvas)
- }
-
- override fun setAlpha(alpha: Int) {
- drawable.alpha = alpha
- }
-
- override fun setColorFilter(colorFilter: ColorFilter?) {
- drawable.colorFilter = colorFilter
- }
-
- @PixelFormat.Opacity
- override fun getOpacity(): Int = PixelFormat.OPAQUE
- }
+ return PersonModel(key, name, drawable, clickIntent, sbn.user.identifier)
}
fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
@@ -272,4 +263,4 @@
if (isMessagingNotification()) key else null
private fun NotificationEntry.isMessagingNotification() =
- sbn.notification.notificationStyle == Notification.MessagingStyle::class.java
\ No newline at end of file
+ sbn.notification.notificationStyle == Notification.MessagingStyle::class.java
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 3c247df..a8a35d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -65,7 +65,6 @@
import android.widget.Chronometer;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -150,7 +149,7 @@
private StatusBarStateController mStatusbarStateController;
private KeyguardBypassController mBypassController;
private LayoutListener mLayoutListener;
- private final NotificationContentInflater mNotificationInflater;
+ private NotificationRowContentBinder mNotificationContentBinder;
private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
private int mMaxHeadsUpHeightBeforeN;
@@ -464,7 +463,7 @@
* Inflate views based off the inflation flags set. Inflation happens asynchronously.
*/
public void inflateViews() {
- mNotificationInflater.bindContent(mEntry, this, mInflationFlags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, mInflationFlags, mBindParams,
false /* forceInflate */, mInflationCallback);
}
@@ -478,7 +477,7 @@
// View should not be reinflated in the future
clearInflationFlags(inflationFlag);
Runnable freeViewRunnable =
- () -> mNotificationInflater.unbindContent(mEntry, this, inflationFlag);
+ () -> mNotificationContentBinder.unbindContent(mEntry, this, inflationFlag);
switch (inflationFlag) {
case FLAG_CONTENT_VIEW_HEADS_UP:
getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
@@ -742,23 +741,10 @@
return mIsHeadsUp || mHeadsupDisappearRunning;
}
-
- public void setGroupManager(NotificationGroupManager groupManager) {
- mGroupManager = groupManager;
- mPrivateLayout.setGroupManager(groupManager);
- }
-
public void setRemoteInputController(RemoteInputController r) {
mPrivateLayout.setRemoteInputController(r);
}
- public void setAppName(String appName) {
- mAppName = appName;
- if (mMenuRow != null && mMenuRow.getMenuView() != null) {
- mMenuRow.setAppName(mAppName);
- }
- }
-
public void addChildNotification(ExpandableNotificationRow row) {
addChildNotification(row, -1);
}
@@ -852,7 +838,7 @@
mIsChildInGroup = isChildInGroup;
if (mIsLowPriority) {
int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
- mNotificationInflater.bindContent(mEntry, this, flags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, flags, mBindParams,
false /* forceInflate */, mInflationCallback);
}
}
@@ -1105,10 +1091,6 @@
return mPrivateLayout.getContractedNotificationHeader();
}
- public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
- mOnExpandClickListener = onExpandClickListener;
- }
-
public void setLongPressListener(LongPressListener longPressListener) {
mLongPressListener = longPressListener;
}
@@ -1131,10 +1113,6 @@
}
}
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
public HeadsUpManager getHeadsUpManager() {
return mHeadsUpManager;
}
@@ -1259,7 +1237,7 @@
l.reInflateViews();
}
mEntry.getSbn().clearPackageContext();
- mNotificationInflater.bindContent(mEntry, this, mInflationFlags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, mInflationFlags, mBindParams,
true /* forceInflate */, mInflationCallback);
}
@@ -1634,10 +1612,6 @@
mBindParams.usesIncreasedHeadsUpHeight = use;
}
- public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
- mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
- }
-
/**
* Set callback for notification content inflation
*
@@ -1652,7 +1626,7 @@
mNeedsRedaction = needsRedaction;
if (needsRedaction) {
setInflationFlags(FLAG_CONTENT_VIEW_PUBLIC);
- mNotificationInflater.bindContent(mEntry, this, FLAG_CONTENT_VIEW_PUBLIC,
+ mNotificationContentBinder.bindContent(mEntry, this, FLAG_CONTENT_VIEW_PUBLIC,
mBindParams, false /* forceInflate */, mInflationCallback);
} else {
clearInflationFlags(FLAG_CONTENT_VIEW_PUBLIC);
@@ -1661,18 +1635,12 @@
}
}
- @VisibleForTesting
- public NotificationContentInflater getNotificationInflater() {
- return mNotificationInflater;
- }
-
public interface ExpansionLogger {
void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
- mNotificationInflater = new NotificationContentInflater();
mMenuRow = new NotificationMenuRow(mContext);
mImageResolver = new NotificationInlineImageResolver(context,
new NotificationInlineImageCache());
@@ -1680,8 +1648,30 @@
initDimens();
}
- public void setBypassController(KeyguardBypassController bypassController) {
+ /**
+ * Initialize row.
+ */
+ public void initialize(
+ String appName,
+ String notificationKey,
+ ExpansionLogger logger,
+ KeyguardBypassController bypassController,
+ NotificationGroupManager groupManager,
+ HeadsUpManager headsUpManager,
+ NotificationRowContentBinder rowContentBinder,
+ OnExpandClickListener onExpandClickListener) {
+ mAppName = appName;
+ if (mMenuRow != null && mMenuRow.getMenuView() != null) {
+ mMenuRow.setAppName(mAppName);
+ }
+ mLogger = logger;
+ mLoggingKey = notificationKey;
mBypassController = bypassController;
+ mGroupManager = groupManager;
+ mPrivateLayout.setGroupManager(groupManager);
+ mHeadsUpManager = headsUpManager;
+ mNotificationContentBinder = rowContentBinder;
+ mOnExpandClickListener = onExpandClickListener;
}
public void setStatusBarStateController(StatusBarStateController statusBarStateController) {
@@ -2920,11 +2910,6 @@
return 0;
}
- public void setExpansionLogger(ExpansionLogger logger, String key) {
- mLogger = logger;
- mLoggingKey = key;
- }
-
public void onExpandedByGesture(boolean userExpanded) {
int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
if (mGroupManager.isSummaryOfGroup(mEntry.getSbn())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java
new file mode 100644
index 0000000..c11c60f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 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.notification.row;
+
+import android.widget.RemoteViews;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+
+/**
+ * Caches {@link RemoteViews} for a notification's content views.
+ */
+public interface NotifRemoteViewCache {
+
+ /**
+ * Whether the notification has the remote view cached
+ *
+ * @param entry notification
+ * @param flag inflation flag for content view
+ * @return true if the remote view is cached
+ */
+ boolean hasCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Get the remote view for the content flag specified.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ * @return the remote view if it is cached, null otherwise
+ */
+ @Nullable RemoteViews getCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Cache a remote view for a given content flag on a notification.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ * @param remoteView remote view to store
+ */
+ void putCachedView(
+ NotificationEntry entry,
+ @InflationFlag int flag,
+ RemoteViews remoteView);
+
+ /**
+ * Remove a cached remote view for a given content flag on a notification.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ */
+ void removeCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Clear a notification's remote view cache.
+ *
+ * @param entry notification
+ */
+ void clearCache(NotificationEntry entry);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java
new file mode 100644
index 0000000..a19099a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 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.notification.row;
+
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Implementation of remote view cache that keeps remote views cached for all active notifications.
+ */
+public class NotifRemoteViewCacheImpl implements NotifRemoteViewCache {
+ private final Map<NotificationEntry, SparseArray<RemoteViews>> mNotifCachedContentViews =
+ new ArrayMap<>();
+
+ @Inject
+ NotifRemoteViewCacheImpl(NotificationEntryManager entryManager) {
+ entryManager.addNotificationEntryListener(mEntryListener);
+ }
+
+ @Override
+ public boolean hasCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ return getCachedView(entry, flag) != null;
+ }
+
+ @Override
+ public @Nullable RemoteViews getCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ return getContentViews(entry).get(flag);
+ }
+
+ @Override
+ public void putCachedView(
+ NotificationEntry entry,
+ @InflationFlag int flag,
+ RemoteViews remoteView) {
+ getContentViews(entry).put(flag, remoteView);
+ }
+
+ @Override
+ public void removeCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ getContentViews(entry).remove(flag);
+ }
+
+ @Override
+ public void clearCache(NotificationEntry entry) {
+ getContentViews(entry).clear();
+ }
+
+ private @NonNull SparseArray<RemoteViews> getContentViews(NotificationEntry entry) {
+ SparseArray<RemoteViews> contentViews = mNotifCachedContentViews.get(entry);
+ if (contentViews == null) {
+ throw new IllegalStateException(
+ String.format("Remote view cache was never created for notification %s",
+ entry.getKey()));
+ }
+ return contentViews;
+ }
+
+ private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationEntry entry) {
+ mNotifCachedContentViews.put(entry, new SparseArray<>());
+ }
+
+ @Override
+ public void onEntryRemoved(
+ NotificationEntry entry,
+ @Nullable NotificationVisibility visibility,
+ boolean removedByUser) {
+ mNotifCachedContentViews.remove(entry);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 30f22ac..e1a6747 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
@@ -26,7 +27,6 @@
import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
@@ -35,6 +35,7 @@
import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
@@ -49,17 +50,30 @@
import java.util.HashMap;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* {@link NotificationContentInflater} binds content to a {@link ExpandableNotificationRow} by
* asynchronously building the content's {@link RemoteViews} and applying it to the row.
*/
+@Singleton
+@VisibleForTesting(visibility = PACKAGE)
public class NotificationContentInflater implements NotificationRowContentBinder {
public static final String TAG = "NotifContentInflater";
- private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private boolean mInflateSynchronously = false;
- private final ArrayMap<Integer, RemoteViews> mCachedContentViews = new ArrayMap<>();
+ private final NotificationRemoteInputManager mRemoteInputManager;
+ private final NotifRemoteViewCache mRemoteViewCache;
+
+ @Inject
+ public NotificationContentInflater(
+ NotifRemoteViewCache remoteViewCache,
+ NotificationRemoteInputManager remoteInputManager) {
+ mRemoteViewCache = remoteViewCache;
+ mRemoteInputManager = remoteInputManager;
+ }
@Override
public void bindContent(
@@ -76,27 +90,27 @@
return;
}
- StatusBarNotification sbn = row.getEntry().getSbn();
+ StatusBarNotification sbn = entry.getSbn();
// To check if the notification has inline image and preload inline image if necessary.
row.getImageResolver().preloadImages(sbn.getNotification());
if (forceInflate) {
- mCachedContentViews.clear();
+ mRemoteViewCache.clearCache(entry);
}
AsyncInflationTask task = new AsyncInflationTask(
- sbn,
mInflateSynchronously,
contentToBind,
- mCachedContentViews,
+ mRemoteViewCache,
+ entry,
row,
bindParams.isLowPriority,
bindParams.isChildInGroup,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
callback,
- mRemoteViewClickHandler);
+ mRemoteInputManager.getRemoteViewsOnClickHandler());
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
} else {
@@ -123,13 +137,15 @@
result = inflateSmartReplyViews(result, reInflateFlags, entry,
row.getContext(), packageContext, row.getHeadsUpManager(),
row.getExistingSmartRepliesAndActions());
+
apply(
inflateSynchronously,
result,
reInflateFlags,
- mCachedContentViews,
+ mRemoteViewCache,
+ entry,
row,
- mRemoteViewClickHandler,
+ mRemoteInputManager.getRemoteViewsOnClickHandler(),
null);
return result;
}
@@ -149,7 +165,7 @@
int curFlag = 1;
while (contentToUnbind != 0) {
if ((contentToUnbind & curFlag) != 0) {
- freeNotificationView(row, curFlag);
+ freeNotificationView(entry, row, curFlag);
}
contentToUnbind &= ~curFlag;
curFlag = curFlag << 1;
@@ -157,34 +173,25 @@
}
/**
- * Set click handler for notification remote views
- *
- * @param remoteViewClickHandler click handler for remote views
- */
- public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
- mRemoteViewClickHandler = remoteViewClickHandler;
- }
-
- /**
* Frees the content view associated with the inflation flag. Will only succeed if the
* view is safe to remove.
*
* @param inflateFlag the flag corresponding to the content view which should be freed
*/
- private void freeNotificationView(ExpandableNotificationRow row,
+ private void freeNotificationView(NotificationEntry entry, ExpandableNotificationRow row,
@InflationFlag int inflateFlag) {
switch (inflateFlag) {
case FLAG_CONTENT_VIEW_HEADS_UP:
if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) {
row.getPrivateLayout().setHeadsUpChild(null);
- mCachedContentViews.remove(FLAG_CONTENT_VIEW_HEADS_UP);
+ mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP);
row.getPrivateLayout().setHeadsUpInflatedSmartReplies(null);
}
break;
case FLAG_CONTENT_VIEW_PUBLIC:
if (row.getPublicLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) {
row.getPublicLayout().setContractedChild(null);
- mCachedContentViews.remove(FLAG_CONTENT_VIEW_PUBLIC);
+ mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC);
}
break;
case FLAG_CONTENT_VIEW_CONTRACTED:
@@ -245,11 +252,12 @@
return result;
}
- public static CancellationSignal apply(
+ private static CancellationSignal apply(
boolean inflateSynchronously,
InflationProgress result,
@InflationFlag int reInflateFlags,
- ArrayMap<Integer, RemoteViews> cachedContentViews,
+ NotifRemoteViewCache remoteViewCache,
+ NotificationEntry entry,
ExpandableNotificationRow row,
RemoteViews.OnClickHandler remoteViewClickHandler,
@Nullable InflationCallback callback) {
@@ -261,7 +269,7 @@
if ((reInflateFlags & flag) != 0) {
boolean isNewView =
!canReapplyRemoteView(result.newContentView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -273,8 +281,8 @@
return result.newContentView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
- row, isNewView, remoteViewClickHandler, callback, privateLayout,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler, callback, privateLayout,
privateLayout.getContractedChild(), privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
@@ -285,7 +293,7 @@
if (result.newExpandedView != null) {
boolean isNewView =
!canReapplyRemoteView(result.newExpandedView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -297,8 +305,8 @@
return result.newExpandedView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
- cachedContentViews, row, isNewView, remoteViewClickHandler,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getExpandedChild(),
privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
@@ -311,7 +319,7 @@
if (result.newHeadsUpView != null) {
boolean isNewView =
!canReapplyRemoteView(result.newHeadsUpView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -323,8 +331,8 @@
return result.newHeadsUpView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
- cachedContentViews, row, isNewView, remoteViewClickHandler,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getHeadsUpChild(),
privateLayout.getVisibleWrapper(
VISIBLE_TYPE_HEADSUP), runningInflations,
@@ -336,7 +344,7 @@
if ((reInflateFlags & flag) != 0) {
boolean isNewView =
!canReapplyRemoteView(result.newPublicView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -348,15 +356,16 @@
return result.newPublicView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
- row, isNewView, remoteViewClickHandler, callback,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler, callback,
publicLayout, publicLayout.getContractedChild(),
publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
}
// Let's try to finish, maybe nobody is even inflating anything
- finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations, callback, row);
+ finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
+ row);
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
() -> runningInflations.values().forEach(CancellationSignal::cancel));
@@ -369,7 +378,8 @@
final InflationProgress result,
final @InflationFlag int reInflateFlags,
@InflationFlag int inflationId,
- final ArrayMap<Integer, RemoteViews> cachedContentViews,
+ final NotifRemoteViewCache remoteViewCache,
+ final NotificationEntry entry,
final ExpandableNotificationRow row,
boolean isNewView,
RemoteViews.OnClickHandler remoteViewClickHandler,
@@ -422,8 +432,8 @@
existingWrapper.onReinflated();
}
runningInflations.remove(inflationId);
- finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations,
- callback, row);
+ finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations,
+ callback, entry, row);
}
@Override
@@ -488,11 +498,11 @@
* @return true if the inflation was finished
*/
private static boolean finishIfDone(InflationProgress result,
- @InflationFlag int reInflateFlags, ArrayMap<Integer, RemoteViews> cachedContentViews,
+ @InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
HashMap<Integer, CancellationSignal> runningInflations,
- @Nullable InflationCallback endListener, ExpandableNotificationRow row) {
+ @Nullable InflationCallback endListener, NotificationEntry entry,
+ ExpandableNotificationRow row) {
Assert.isMainThread();
- NotificationEntry entry = row.getEntry();
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
if (runningInflations.isEmpty()) {
@@ -500,23 +510,27 @@
if (result.inflatedContentView != null) {
// New view case
privateLayout.setContractedChild(result.inflatedContentView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED) != null) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED,
+ result.newContentView);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED)) {
// Reinflation case. Only update if it's still cached (i.e. view has not been
// freed while inflating).
- cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED,
+ result.newContentView);
}
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
if (result.inflatedExpandedView != null) {
privateLayout.setExpandedChild(result.inflatedExpandedView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED,
+ result.newExpandedView);
} else if (result.newExpandedView == null) {
privateLayout.setExpandedChild(null);
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, null);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
+ remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED,
+ result.newExpandedView);
}
if (result.newExpandedView != null) {
privateLayout.setExpandedInflatedSmartReplies(
@@ -530,12 +544,14 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
if (result.inflatedHeadsUpView != null) {
privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP,
+ result.newHeadsUpView);
} else if (result.newHeadsUpView == null) {
privateLayout.setHeadsUpChild(null);
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, null);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
+ remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP,
+ result.newHeadsUpView);
}
if (result.newHeadsUpView != null) {
privateLayout.setHeadsUpInflatedSmartReplies(
@@ -548,16 +564,18 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
if (result.inflatedPublicView != null) {
publicLayout.setContractedChild(result.inflatedPublicView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC,
+ result.newPublicView);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC,
+ result.newPublicView);
}
}
entry.headsUpStatusBarText = result.headsUpStatusBarText;
entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
if (endListener != null) {
- endListener.onAsyncInflationFinished(row.getEntry(), reInflateFlags);
+ endListener.onAsyncInflationFinished(entry, reInflateFlags);
}
return true;
}
@@ -615,7 +633,7 @@
public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
implements InflationCallback, InflationTask {
- private final StatusBarNotification mSbn;
+ private final NotificationEntry mEntry;
private final Context mContext;
private final boolean mInflateSynchronously;
private final boolean mIsLowPriority;
@@ -624,17 +642,17 @@
private final InflationCallback mCallback;
private final boolean mUsesIncreasedHeadsUpHeight;
private @InflationFlag int mReInflateFlags;
- private final ArrayMap<Integer, RemoteViews> mCachedContentViews;
+ private final NotifRemoteViewCache mRemoteViewCache;
private ExpandableNotificationRow mRow;
private Exception mError;
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private CancellationSignal mCancellationSignal;
private AsyncInflationTask(
- StatusBarNotification notification,
boolean inflateSynchronously,
@InflationFlag int reInflateFlags,
- ArrayMap<Integer, RemoteViews> cachedContentViews,
+ NotifRemoteViewCache cache,
+ NotificationEntry entry,
ExpandableNotificationRow row,
boolean isLowPriority,
boolean isChildInGroup,
@@ -642,11 +660,11 @@
boolean usesIncreasedHeadsUpHeight,
InflationCallback callback,
RemoteViews.OnClickHandler remoteViewClickHandler) {
+ mEntry = entry;
mRow = row;
- mSbn = notification;
mInflateSynchronously = inflateSynchronously;
mReInflateFlags = reInflateFlags;
- mCachedContentViews = cachedContentViews;
+ mRemoteViewCache = cache;
mContext = mRow.getContext();
mIsLowPriority = isLowPriority;
mIsChildInGroup = isChildInGroup;
@@ -654,7 +672,6 @@
mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
mRemoteViewClickHandler = remoteViewClickHandler;
mCallback = callback;
- NotificationEntry entry = row.getEntry();
entry.setInflationTask(this);
}
@@ -667,12 +684,13 @@
@Override
protected InflationProgress doInBackground(Void... params) {
try {
+ final StatusBarNotification sbn = mEntry.getSbn();
final Notification.Builder recoveredBuilder
= Notification.Builder.recoverBuilder(mContext,
- mSbn.getNotification());
+ sbn.getNotification());
- Context packageContext = mSbn.getPackageContext(mContext);
- Notification notification = mSbn.getNotification();
+ Context packageContext = sbn.getPackageContext(mContext);
+ Notification notification = sbn.getNotification();
if (notification.isMediaNotification()) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
packageContext);
@@ -681,7 +699,7 @@
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext);
- return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mRow.getEntry(),
+ return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mEntry,
mRow.getContext(), packageContext, mRow.getHeadsUpManager(),
mRow.getExistingSmartRepliesAndActions());
} catch (Exception e) {
@@ -694,15 +712,15 @@
protected void onPostExecute(InflationProgress result) {
if (mError == null) {
mCancellationSignal = apply(mInflateSynchronously, result, mReInflateFlags,
- mCachedContentViews, mRow, mRemoteViewClickHandler, this);
+ mRemoteViewCache, mEntry, mRow, mRemoteViewClickHandler, this);
} else {
handleError(mError);
}
}
private void handleError(Exception e) {
- mRow.getEntry().onInflationTaskFinished();
- StatusBarNotification sbn = mRow.getEntry().getSbn();
+ mEntry.onInflationTaskFinished();
+ StatusBarNotification sbn = mEntry.getSbn();
final String ident = sbn.getPackageName() + "/0x"
+ Integer.toHexString(sbn.getId());
Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
@@ -736,10 +754,10 @@
@Override
public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
- mRow.getEntry().onInflationTaskFinished();
+ mEntry.onInflationTaskFinished();
mRow.onNotificationUpdated();
if (mCallback != null) {
- mCallback.onAsyncInflationFinished(mRow.getEntry(), inflatedFlags);
+ mCallback.onAsyncInflationFinished(mEntry, inflatedFlags);
}
// Notify the resolver that the inflation task has finished,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
new file mode 100644
index 0000000..df8653c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.notification.row;
+
+import javax.inject.Singleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Dagger Module containing notification row and view inflation implementations.
+ */
+@Module
+public abstract class NotificationRowModule {
+ /**
+ * Provides notification row content binder instance.
+ */
+ @Binds
+ @Singleton
+ public abstract NotificationRowContentBinder provideNotificationRowContentBinder(
+ NotificationContentInflater contentBinderImpl);
+
+ /**
+ * Provides notification remote view cache instance.
+ */
+ @Binds
+ @Singleton
+ public abstract NotifRemoteViewCache provideNotifRemoteViewCache(
+ NotifRemoteViewCacheImpl cacheImpl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 2761689..09c1fad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -187,18 +187,18 @@
@Override
public boolean beginsSection(@NonNull View view, @Nullable View previous) {
boolean begin = false;
- if (view instanceof ExpandableNotificationRow) {
- if (previous instanceof ExpandableNotificationRow) {
+ if (view instanceof ActivatableNotificationView) {
+ if (previous instanceof ActivatableNotificationView) {
// If we're drawing the first non-person notification, break out a section
- ExpandableNotificationRow curr = (ExpandableNotificationRow) view;
- ExpandableNotificationRow prev = (ExpandableNotificationRow) previous;
+ ActivatableNotificationView curr = (ActivatableNotificationView) view;
+ ActivatableNotificationView prev = (ActivatableNotificationView) previous;
- begin = curr.getEntry().getBucket() != prev.getEntry().getBucket();
+ begin = getBucket(curr) != getBucket(prev);
}
}
if (!begin) {
- begin = view == mGentleHeader || previous == mPeopleHubView;
+ begin = view == mGentleHeader || view == mPeopleHubView;
}
return begin;
@@ -230,29 +230,42 @@
return;
}
- int lastPersonIndex = -1;
- int firstGentleNotifIndex = -1;
+ boolean peopleNotificationsPresent = false;
+ int firstNonHeadsUpIndex = -1;
+ int firstGentleIndex = -1;
+ int notifCount = 0;
final int n = mParent.getChildCount();
for (int i = 0; i < n; i++) {
View child = mParent.getChildAt(i);
- if (child instanceof ExpandableNotificationRow
- && child.getVisibility() != View.GONE) {
+ if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
+ notifCount++;
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) {
+ firstNonHeadsUpIndex = i;
+ }
if (row.getEntry().getBucket() == BUCKET_PEOPLE) {
- lastPersonIndex = i;
+ peopleNotificationsPresent = true;
}
if (row.getEntry().getBucket() == BUCKET_SILENT) {
- firstGentleNotifIndex = i;
+ firstGentleIndex = i;
break;
}
}
}
- // make room for peopleHub
- firstGentleNotifIndex += adjustPeopleHubVisibilityAndPosition(lastPersonIndex);
+ if (firstNonHeadsUpIndex == -1) {
+ firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount;
+ }
- adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
+ // make room for peopleHub
+ int offset = adjustPeopleHubVisibilityAndPosition(
+ firstNonHeadsUpIndex, peopleNotificationsPresent);
+ if (firstGentleIndex != -1) {
+ firstGentleIndex += offset;
+ }
+
+ adjustGentleHeaderVisibilityAndPosition(firstGentleIndex);
mGentleHeader.setAreThereDismissableGentleNotifs(
mParent.hasActiveClearableNotifications(ROWS_GENTLE));
@@ -294,13 +307,15 @@
}
}
- private int adjustPeopleHubVisibilityAndPosition(int lastPersonIndex) {
- final boolean showPeopleHeader = mPeopleHubVisible
- && mNumberOfSections > 2
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
+ private int adjustPeopleHubVisibilityAndPosition(
+ int targetIndex, boolean peopleNotificationsPresent) {
+ final boolean showPeopleHeader = mNumberOfSections > 2
+ && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+ && (peopleNotificationsPresent || mPeopleHubVisible);
final int currentHubIndex = mParent.indexOfChild(mPeopleHubView);
final boolean currentlyVisible = currentHubIndex >= 0;
- int targetIndex = lastPersonIndex + 1;
+
+ mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent);
if (!showPeopleHeader) {
if (currentlyVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 6d0fcc3..4845ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -31,6 +31,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@@ -298,8 +299,8 @@
@Override
public Animator getViewTranslationAnimator(View v, float target,
ValueAnimator.AnimatorUpdateListener listener) {
- if (v instanceof SwipeableView) {
- return ((SwipeableView) v).getTranslateViewAnimator(target, listener);
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
} else {
return superGetViewTranslationAnimator(v, target, listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index a079606..e5717ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -16,38 +16,22 @@
package com.android.systemui.statusbar.notification.stack
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
-import android.util.FloatProperty
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
import com.android.systemui.statusbar.notification.people.DataListener
import com.android.systemui.statusbar.notification.people.PersonViewModel
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") {
- override fun setValue(view: PeopleHubView, value: Float) {
- view.translation = value
- }
-
- override fun get(view: PeopleHubView) = view.translation
-}
-
class PeopleHubView(context: Context, attrs: AttributeSet) :
ActivatableNotificationView(context, attrs), SwipeableView {
private lateinit var contents: ViewGroup
private lateinit var personControllers: List<PersonDataListenerImpl>
- private var translateAnim: ObjectAnimator? = null
val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
get() = personControllers.asSequence()
@@ -56,9 +40,10 @@
super.onFinishInflate()
contents = requireViewById(R.id.people_list)
personControllers = (0 until contents.childCount)
+ .reversed()
.asSequence()
.mapNotNull { idx ->
- (contents.getChildAt(idx) as? LinearLayout)?.let(::PersonDataListenerImpl)
+ (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
}
.toList()
}
@@ -69,41 +54,32 @@
override fun createMenu(): NotificationMenuRowPlugin? = null
- override fun getTranslateViewAnimator(
- leftTarget: Float,
- listener: ValueAnimator.AnimatorUpdateListener?
- ): Animator =
- ObjectAnimator
- .ofFloat(this, TRANSLATE_CONTENT, leftTarget)
- .apply {
- listener?.let { addUpdateListener(listener) }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(anim: Animator) {
- translateAnim = null
- }
- })
- }
- .also {
- translateAnim?.cancel()
- translateAnim = it
- }
-
override fun resetTranslation() {
- translateAnim?.cancel()
translationX = 0f
}
- private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) :
+ override fun setTranslation(translation: Float) {
+ if (canSwipe) {
+ super.setTranslation(translation)
+ }
+ }
+
+ var canSwipe: Boolean = true
+ set(value) {
+ if (field != value) {
+ if (field) {
+ resetTranslation()
+ }
+ field = value
+ }
+ }
+
+ private inner class PersonDataListenerImpl(val avatarView: ImageView) :
DataListener<PersonViewModel?> {
- val nameView = viewGroup.requireViewById<TextView>(R.id.person_name)
- val avatarView = viewGroup.requireViewById<ImageView>(R.id.person_icon)
-
override fun onDataChanged(data: PersonViewModel?) {
- viewGroup.visibility = data?.let { View.VISIBLE } ?: View.INVISIBLE
- nameView.text = data?.name
avatarView.setImageDrawable(data?.icon)
- viewGroup.setOnClickListener { data?.onClick?.invoke() }
+ avatarView.setOnClickListener { data?.onClick?.invoke() }
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
index 6c6ef61..49e59a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-
import androidx.annotation.Nullable;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -32,10 +29,6 @@
/** Optionally creates a menu for this view. */
@Nullable NotificationMenuRowPlugin createMenu();
- /** Animator for translating the view, simulating a swipe. */
- Animator getTranslateViewAnimator(
- float leftTarget, ValueAnimator.AnimatorUpdateListener listener);
-
/** Sets the translation amount for an in-progress swipe. */
void setTranslation(float translate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index f7d52b5..ad1aa83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -98,7 +98,12 @@
bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
}
}, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
- lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
+ lockscreenUserManager.addUserChangedListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) {
+ pendingUnlockType = null
+ }
+ })
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index fe0739f..896b6e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -32,7 +32,6 @@
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
@@ -428,7 +427,7 @@
* The notification is still pending inflation but we've decided that we no longer need
* the content view (e.g. suppression might have changed and we decided we need to transfer
* back). However, there is no way to abort just this inflation if other inflation requests
- * have started (see {@link AsyncInflationTask#supersedeTask(InflationTask)}). So instead
+ * have started (see {@link InflationTask#supersedeTask(InflationTask)}). So instead
* we just flag it as aborted and free when it's inflated.
*/
boolean mAbortOnInflation;
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 9dc8fbf..0f3af09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,8 +24,6 @@
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
-import com.android.internal.annotations.VisibleForTesting;
-
public class NotificationPanelView extends PanelView {
private static final boolean DEBUG = false;
@@ -38,14 +36,10 @@
static final String COUNTER_PANEL_OPEN = "panel_open";
static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
- @VisibleForTesting
- protected KeyguardAffordanceHelper mAffordanceHelper;
-
- private int mOldLayoutDirection;
-
private int mCurrentPanelAlpha;
private final Paint mAlphaPaint = new Paint();
private boolean mDozing;
+ private RtlChangeListener mRtlChangeListener;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -57,9 +51,8 @@
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
- if (layoutDirection != mOldLayoutDirection) {
- mAffordanceHelper.onRtlPropertiesChanged();
- mOldLayoutDirection = layoutDirection;
+ if (mRtlChangeListener != null) {
+ mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
}
}
@@ -95,4 +88,11 @@
return !mDozing;
}
+ void setRtlChangeListener(RtlChangeListener listener) {
+ mRtlChangeListener = listener;
+ }
+
+ interface RtlChangeListener {
+ void onRtlPropertielsChanged(int layoutDirection);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index bbde25b..90ec2a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -449,6 +449,7 @@
private PluginManager mPluginManager;
private FrameLayout mPluginFrame;
private NPVPluginManager mNPVPluginManager;
+ private int mOldLayoutDirection;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -603,6 +604,13 @@
}
}, HomeControlsPlugin.class, false);
+
+ mView.setRtlChangeListener(layoutDirection -> {
+ if (layoutDirection != mOldLayoutDirection) {
+ mAffordanceHelper.onRtlPropertiesChanged();
+ mOldLayoutDirection = layoutDirection;
+ }
+ });
}
@Override
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 ccc86b1..30825ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -205,6 +205,7 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -413,6 +414,7 @@
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
private final NotificationEntryManager mEntryManager;
+ private final NotificationRowContentBinder mRowContentBinder;
private NotificationListController mNotificationListController;
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
@@ -634,6 +636,7 @@
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -715,6 +718,7 @@
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mEntryManager = notificationEntryManager;
+ mRowContentBinder = notificationRowContentBinder;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
@@ -1240,6 +1244,7 @@
final NotificationRowBinderImpl rowBinder =
new NotificationRowBinderImpl(
mContext,
+ mRowContentBinder,
mAllowNotificationLongPress,
mKeyguardBypassController,
mStatusBarStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 153ca22..df74107 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -69,6 +69,7 @@
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -125,6 +126,7 @@
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -207,6 +209,7 @@
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
new file mode 100644
index 0000000..d413308
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -0,0 +1,333 @@
+/*
+ * 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.wm;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowInsets;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
+ */
+@Singleton
+public class DisplayImeController implements DisplayWindowController.DisplayWindowListener {
+ private static final String TAG = "DisplayImeController";
+
+ static final int ANIMATION_DURATION_SHOW_MS = 275;
+ static final int ANIMATION_DURATION_HIDE_MS = 340;
+ static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ private static final int DIRECTION_NONE = 0;
+ private static final int DIRECTION_SHOW = 1;
+ private static final int DIRECTION_HIDE = 2;
+
+ SystemWindows mSystemWindows;
+ final Handler mHandler;
+
+ final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
+
+ final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
+
+ @Inject
+ DisplayImeController(SystemWindows syswin, DisplayWindowController displayController,
+ @Main Handler mainHandler) {
+ mHandler = mainHandler;
+ mSystemWindows = syswin;
+ displayController.addDisplayWindowListener(this);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // Add's a system-ui window-manager specifically for ime. This type is special because
+ // WM will defer IME inset handling to it in multi-window scenarious.
+ PerDisplay pd = new PerDisplay(displayId,
+ mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation());
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to set insets controller on display " + displayId);
+ }
+ mImePerDisplay.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
+ != pd.mRotation && isImeShowing(displayId)) {
+ pd.startAnimation(true);
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+ }
+ mImePerDisplay.remove(displayId);
+ }
+
+ private boolean isImeShowing(int displayId) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return false;
+ }
+ final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME);
+ return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible();
+ }
+
+ private void dispatchPositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImePositionChanged(displayId, imeTop, t);
+ }
+ }
+ }
+
+ private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop,
+ boolean show, SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t);
+ }
+ }
+ }
+
+ private void dispatchEndPositioning(int displayId, int imeTop, boolean show,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeEndPositioning(displayId, imeTop, show, t);
+ }
+ }
+ }
+
+ /**
+ * Adds an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void addPositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ if (mPositionProcessors.contains(processor)) {
+ return;
+ }
+ mPositionProcessors.add(processor);
+ }
+ }
+
+ /**
+ * Removes an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void removePositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ mPositionProcessors.remove(processor);
+ }
+ }
+
+ class PerDisplay extends IDisplayWindowInsetsController.Stub {
+ final int mDisplayId;
+ final InsetsState mInsetsState = new InsetsState();
+ InsetsSourceControl mImeSourceControl = null;
+ int mAnimationDirection = DIRECTION_NONE;
+ ValueAnimator mAnimation = null;
+ int mRotation = Surface.ROTATION_0;
+
+ PerDisplay(int displayId, int initialRotation) {
+ mDisplayId = displayId;
+ mRotation = initialRotation;
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+ mInsetsState.set(insetsState, true /* copySources */);
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ insetsChanged(insetsState);
+ if (activeControls != null) {
+ for (InsetsSourceControl activeControl : activeControls) {
+ if (activeControl == null) {
+ continue;
+ }
+ if (activeControl.getType() == InsetsState.ITYPE_IME) {
+ mImeSourceControl = activeControl;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(true /* show */);
+ }
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(false /* show */);
+ }
+
+ /**
+ * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
+ */
+ private void setVisibleDirectly(boolean visible) {
+ mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ try {
+ mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private int imeTop(InsetsSource imeSource, float surfaceOffset) {
+ return imeSource.getFrame().top + (int) surfaceOffset;
+ }
+
+ private void startAnimation(final boolean show) {
+ final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
+ if (imeSource == null || mImeSourceControl == null) {
+ return;
+ }
+ if ((mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ if (mAnimationDirection != DIRECTION_NONE) {
+ mAnimation.end();
+ mAnimationDirection = DIRECTION_NONE;
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
+ mHandler.post(() -> {
+ final float defaultY = mImeSourceControl.getSurfacePosition().y;
+ final float x = mImeSourceControl.getSurfacePosition().x;
+ final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY;
+ final float endY = show ? defaultY : defaultY + imeSource.getFrame().height();
+ mAnimation = ValueAnimator.ofFloat(startY, endY);
+ mAnimation.setDuration(
+ show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ float value = (float) animation.getAnimatedValue();
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
+ dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
+ t.apply();
+ t.close();
+ });
+ mAnimation.setInterpolator(INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
+ imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
+ t);
+ if (mAnimationDirection == DIRECTION_SHOW) {
+ t.show(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
+ mAnimationDirection == DIRECTION_SHOW, t);
+ if (mAnimationDirection == DIRECTION_HIDE) {
+ t.hide(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+
+ mAnimationDirection = DIRECTION_NONE;
+ mAnimation = null;
+ }
+ });
+ if (!show) {
+ // When going away, queue up insets change first, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(false /* visible */);
+ }
+ mAnimation.start();
+ if (show) {
+ // When showing away, queue up insets change last, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(true /* visible */);
+ }
+ });
+ }
+ }
+
+ /**
+ * Allows other things to synchronize with the ime position
+ */
+ public interface ImePositionProcessor {
+ /**
+ * Called when the IME position is starting to animate.
+ */
+ void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing,
+ SurfaceControl.Transaction t);
+
+ /**
+ * Called when the ime position changed. This is expected to be a synchronous call on the
+ * animation thread. Operations can be added to the transaction to be applied in sync.
+ */
+ void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t);
+
+ /**
+ * Called when the IME position is done animating.
+ */
+ void onImeEndPositioning(int displayId, int imeTop, boolean showing,
+ SurfaceControl.Transaction t);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index b70fdbd..eccf096 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -19,7 +19,7 @@
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
@@ -83,14 +83,14 @@
private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
private static final int TEST_CARRIER_ID = 1;
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_NULL = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, null, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
+ TEST_CARRIER, null, NAME_SOURCE_DEFAULT, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
null, null, null, null, false, null, "");
private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
@Mock
private WifiManager mWifiManager;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 40ea6dd..0c22aae 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,7 @@
package com.android.keyguard;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static com.google.common.truth.Truth.assertThat;
@@ -84,11 +84,11 @@
private static final int TEST_CARRIER_ID = 1;
private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
- TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 77659df..3fdbd3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -47,6 +47,9 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpansionLogger;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewCache;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -72,6 +75,7 @@
public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
private static final String GROUP_KEY = "gruKey";
+ private static final String APP_NAME = "appName";
private final Context mContext;
private int mId;
@@ -303,9 +307,6 @@
null /* root */,
false /* attachToRoot */);
ExpandableNotificationRow row = mRow;
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setAboveShelfChangedListener(aboveShelf -> {});
final NotificationChannel channel =
new NotificationChannel(
@@ -329,6 +330,23 @@
entry.setRow(row);
entry.createIcons(mContext, entry.getSbn());
row.setEntry(entry);
+
+ NotificationContentInflater contentBinder = new NotificationContentInflater(
+ mock(NotifRemoteViewCache.class),
+ mock(NotificationRemoteInputManager.class));
+ contentBinder.setInflateSynchronously(true);
+
+ row.initialize(
+ APP_NAME,
+ entry.getKey(),
+ mock(ExpansionLogger.class),
+ mock(KeyguardBypassController.class),
+ mGroupManager,
+ mHeadsUpManager,
+ contentBinder,
+ mock(OnExpandClickListener.class));
+ row.setAboveShelfChangedListener(aboveShelf -> { });
+
row.setInflationFlags(extraInflationFlags);
inflateAndWait(row);
@@ -341,7 +359,6 @@
private static void inflateAndWait(ExpandableNotificationRow row) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(1);
- row.getNotificationInflater().setInflateSynchronously(true);
NotificationContentInflater.InflationCallback callback =
new NotificationContentInflater.InflationCallback() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index c559265..1c29453 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -87,7 +87,10 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewCache;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -241,8 +244,14 @@
mEntryManager.addNotificationEntryListener(mEntryListener);
mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
+ NotificationRowContentBinder contentBinder = new NotificationContentInflater(
+ mock(NotifRemoteViewCache.class),
+ mRemoteInputManager);
+
NotificationRowBinderImpl notificationRowBinder =
- new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
+ new NotificationRowBinderImpl(mContext,
+ contentBinder,
+ true, /* allowLongPress */
mock(KeyguardBypassController.class),
mock(StatusBarStateController.class),
mock(NotificationLogger.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 0837a42..28feaca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -261,9 +262,13 @@
.setRank(5)
.setExplanation("baz buzz")
.build();
+
+ // WHEN entry3's ranking update includes an update to its overrideGroupKey
+ final String newOverrideGroupKey = "newOverrideGroupKey";
Ranking newRanking3 = new RankingBuilder(notif3.ranking)
.setRank(6)
.setExplanation("Penguin pizza")
+ .setOverrideGroupKey(newOverrideGroupKey)
.build();
mNoMan.setRanking(notif1.sbn.getKey(), newRanking1);
@@ -275,6 +280,10 @@
assertEquals(newRanking1, entry1.getRanking());
assertEquals(newRanking2, entry2.getRanking());
assertEquals(newRanking3, entry3.getRanking());
+
+ // THEN the entry3's overrideGroupKey is updated along with its groupKey
+ assertEquals(newOverrideGroupKey, entry3.getSbn().getOverrideGroupKey());
+ assertNotNull(entry3.getSbn().getGroupKey());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 0764d0c..867a9b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -178,9 +178,10 @@
private fun fakePersonModel(
id: String,
name: CharSequence,
- clickIntent: PendingIntent
+ clickIntent: PendingIntent,
+ userId: Int = 0
): PersonModel =
- PersonModel(id, name, mock(Drawable::class.java), clickIntent)
+ PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId)
private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
@@ -207,4 +208,4 @@
override fun onDataChanged(data: T) {
lastSeen = Maybe.Just(data)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
new file mode 100644
index 0000000..d7214f3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 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.notification.row;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.widget.RemoteViews;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class NotifRemoteViewCacheImplTest extends SysuiTestCase {
+
+ private NotifRemoteViewCacheImpl mNotifRemoteViewCache;
+ private NotificationEntry mEntry;
+ private NotificationEntryListener mEntryListener;
+ @Mock private RemoteViews mRemoteViews;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mEntry = new NotificationEntryBuilder().build();
+
+ NotificationEntryManager entryManager = mock(NotificationEntryManager.class);
+ mNotifRemoteViewCache = new NotifRemoteViewCacheImpl(entryManager);
+ ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
+ ArgumentCaptor.forClass(NotificationEntryListener.class);
+ verify(entryManager).addNotificationEntryListener(entryListenerCaptor.capture());
+ mEntryListener = entryListenerCaptor.getValue();
+ }
+
+ @Test
+ public void testPutCachedView() {
+ // GIVEN an initialized cache for an entry.
+ mEntryListener.onPendingEntryAdded(mEntry);
+
+ // WHEN a notification's cached remote views is put in.
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+
+ // THEN the remote view is cached.
+ assertTrue(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ assertEquals(
+ "Cached remote view is not the one we put in.",
+ mRemoteViews,
+ mNotifRemoteViewCache.getCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ }
+
+ @Test
+ public void testRemoveCachedView() {
+ // GIVEN a cache with a cached view.
+ mEntryListener.onPendingEntryAdded(mEntry);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+
+ // WHEN we remove the cached view.
+ mNotifRemoteViewCache.removeCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED);
+
+ // THEN the remote view is not cached.
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ }
+
+ @Test
+ public void testClearCache() {
+ // GIVEN a non-empty cache.
+ mEntryListener.onPendingEntryAdded(mEntry);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_EXPANDED, mRemoteViews);
+
+ // WHEN we clear the cache.
+ mNotifRemoteViewCache.clearCache(mEntry);
+
+ // THEN the cache is empty.
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_EXPANDED));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index f916fe5..cb9da6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -22,11 +22,16 @@
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
@@ -35,16 +40,17 @@
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams;
@@ -57,6 +63,8 @@
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
@@ -73,8 +81,11 @@
private Notification.Builder mBuilder;
private ExpandableNotificationRow mRow;
+ @Mock private NotifRemoteViewCache mCache;
+
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mBuilder = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
.setContentTitle("Title")
@@ -83,7 +94,9 @@
ExpandableNotificationRow row = new NotificationTestHelper(mContext, mDependency).createRow(
mBuilder.build());
mRow = spy(row);
- mNotificationInflater = new NotificationContentInflater();
+ mNotificationInflater = new NotificationContentInflater(
+ mCache,
+ mock(NotificationRemoteInputManager.class));
}
@Test
@@ -174,7 +187,9 @@
result,
FLAG_CONTENT_VIEW_EXPANDED,
0,
- new ArrayMap() /* cachedContentViews */, mRow,
+ mock(NotifRemoteViewCache.class),
+ mRow.getEntry(),
+ mRow,
true /* isNewView */, (v, p, r) -> true,
new InflationCallback() {
@Override
@@ -244,6 +259,71 @@
NotificationContentInflater.canReapplyRemoteView(mediaView, decoratedMediaView));
}
+ @Test
+ public void testUsesSameViewWhenCachedPossibleToReuse() throws Exception {
+ // GIVEN a cached view.
+ RemoteViews contractedRemoteView = mBuilder.createContentView();
+ when(mCache.hasCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(true);
+ when(mCache.getCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(contractedRemoteView);
+
+ // GIVEN existing bound view with same layout id.
+ View view = contractedRemoteView.apply(mContext, null /* parent */);
+ mRow.getPrivateLayout().setContractedChild(view);
+
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN the view should be re-used
+ assertEquals("Binder inflated a new view even though the old one was cached and usable.",
+ view, mRow.getPrivateLayout().getContractedChild());
+ }
+
+ @Test
+ public void testInflatesNewViewWhenCachedNotPossibleToReuse() throws Exception {
+ // GIVEN a cached remote view.
+ RemoteViews contractedRemoteView = mBuilder.createHeadsUpContentView();
+ when(mCache.hasCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(true);
+ when(mCache.getCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(contractedRemoteView);
+
+ // GIVEN existing bound view with different layout id.
+ View view = new TextView(mContext);
+ mRow.getPrivateLayout().setContractedChild(view);
+
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN the view should be a new view
+ assertNotEquals("Binder (somehow) used the same view when inflating.",
+ view, mRow.getPrivateLayout().getContractedChild());
+ }
+
+ @Test
+ public void testInflationCachesCreatedRemoteView() throws Exception {
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN inflater informs cache of the new remote view
+ verify(mCache).putCachedView(
+ eq(mRow.getEntry()),
+ eq(FLAG_CONTENT_VIEW_CONTRACTED),
+ any());
+ }
+
+ @Test
+ public void testUnbindRemovesCachedRemoteView() {
+ // WHEN inflated unbinds content
+ mNotificationInflater.unbindContent(mRow.getEntry(), mRow, FLAG_CONTENT_VIEW_HEADS_UP);
+
+ // THEN inflated informs cache to remove remote view
+ verify(mCache).removeCachedView(
+ eq(mRow.getEntry()),
+ eq(FLAG_CONTENT_VIEW_HEADS_UP));
+ }
+
private static void inflateAndWait(NotificationContentInflater inflater,
@InflationFlag int contentToInflate,
ExpandableNotificationRow row)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 7e485f4..3da87ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -122,6 +122,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -247,6 +248,7 @@
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private NotificationEntryManager mEntryManager;
+ @Mock private NotificationContentInflater mNotificationContentInflater;
@Mock private LockscreenLockIconController mLockscreenLockIconController;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
@@ -356,6 +358,7 @@
mNotificationGutsManager,
notificationLogger,
mEntryManager,
+ mNotificationContentInflater,
mNotificationInterruptionStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index f4c2777..5b79d51 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -447,44 +447,33 @@
validate();
return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
}
- native long rsnAllocationCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+
+ native long rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(), usage);
+ return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp,
int usage) {
validate();
- return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp.getNativeInstance(),
- usage);
+ return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(),
- usage);
- }
- native long rsnAllocationCreateBitmapRef(long con, long type, long bitmapHandle);
- synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
- validate();
- return rsnAllocationCreateBitmapRef(mContext, type, bmp.getNativeInstance());
- }
- native long rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
- synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
- validate();
- return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
+ return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native void rsnAllocationCopyToBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyToBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyToBitmap(mContext, alloc, bmp);
}
native void rsnAllocationSyncAll(long con, long alloc, int src);
@@ -537,10 +526,10 @@
validate();
rsnAllocationGenerateMipmaps(mContext, alloc);
}
- native void rsnAllocationCopyFromBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyFromBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0854b95..f9ef0b7 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -12,7 +12,6 @@
libRS \
libcutils \
liblog \
- libhwui \
libutils \
libui \
libgui \
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index dfee961..5ae895d 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -32,10 +32,10 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
+#include <android/graphics/bitmap.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/android_util_AssetManager.h"
-#include "android/graphics/GraphicsJNI.h"
#include "android/native_window.h"
#include "android/native_window_jni.h"
@@ -1319,27 +1319,28 @@
rsAllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
}
+static size_t computeByteSize(const android::graphics::Bitmap& bitmap) {
+ AndroidBitmapInfo info = bitmap.getInfo();
+ return info.height * info.stride;
+}
+
static jlong
nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static jlong
nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
- jint mip, jlong bitmapPtr, jint usage)
+ jint mip, jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
@@ -1349,40 +1350,35 @@
static jlong
nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
- int w = bitmap.width();
- int h = bitmap.height();
+ android::graphics::Bitmap bitmap(_env, jbitmap);
+ int w = bitmap.getInfo().width;
+ int h = bitmap.getInfo().height;
const void* ptr = bitmap.getPixels();
rsAllocation2DData((RsContext)con, (RsAllocation)alloc, 0, 0,
0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X,
- w, h, ptr, bitmap.computeByteSize(), 0);
+ w, h, ptr, computeByteSize(bitmap), 0);
}
static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
void* ptr = bitmap.getPixels();
- rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, bitmap.computeByteSize());
+ rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, computeByteSize(bitmap));
bitmap.notifyPixelsChanged();
}
@@ -2867,12 +2863,12 @@
{"rsnTypeGetNativeData", "(JJ[J)V", (void*)nTypeGetNativeData },
{"rsnAllocationCreateTyped", "(JJIIJ)J", (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap", "(JJIJI)J", (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation", "(JJIJI)J", (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJIJI)J", (void*)nAllocationCubeCreateFromBitmap },
+{"rsnAllocationCreateFromBitmap", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateFromBitmap },
+{"rsnAllocationCreateBitmapBackedAllocation", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateBitmapBackedAllocation },
+{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCubeCreateFromBitmap },
-{"rsnAllocationCopyFromBitmap", "(JJJ)V", (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap", "(JJJ)V", (void*)nAllocationCopyToBitmap },
+{"rsnAllocationCopyFromBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyFromBitmap },
+{"rsnAllocationCopyToBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(JJI)V", (void*)nAllocationSyncAll },
{"rsnAllocationSetupBufferQueue", "(JJI)V", (void*)nAllocationSetupBufferQueue },
diff --git a/services/Android.bp b/services/Android.bp
index 1e11936..5afed6c 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -113,7 +113,7 @@
srcs: [":services-sources"],
installable: false,
// TODO: remove the --hide options below
- args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
+ args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd8a361..4515be8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3029,25 +3029,9 @@
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
// Finish setting up the full connection
- mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
- AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- // A network factory has connected. Send it all current NetworkRequests.
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.isListen()) continue;
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo nai = nri.mSatisfier;
- final int score;
- final int serial;
- if (nai != null) {
- score = nai.getCurrentScore();
- serial = nai.factorySerialNumber;
- } else {
- score = 0;
- serial = NetworkFactory.SerialNumber.NONE;
- }
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
- nri.request);
- }
+ NetworkFactoryInfo nfi = mNetworkFactoryInfos.get(msg.replyTo);
+ nfi.completeConnection();
+ sendAllRequestsToFactory(nfi);
} else {
loge("Error connecting NetworkFactory");
mNetworkFactoryInfos.remove(msg.obj);
@@ -3430,8 +3414,7 @@
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
- nri.request);
+ nfi.cancelRequest(nri.request);
}
} else {
// listens don't have a singular affectedNetwork. Check all networks to see
@@ -4927,16 +4910,33 @@
private static class NetworkFactoryInfo {
public final String name;
public final Messenger messenger;
- public final AsyncChannel asyncChannel;
+ private final AsyncChannel mAsyncChannel;
public final int factorySerialNumber;
NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
int factorySerialNumber) {
this.name = name;
this.messenger = messenger;
- this.asyncChannel = asyncChannel;
+ this.mAsyncChannel = asyncChannel;
this.factorySerialNumber = factorySerialNumber;
}
+
+ void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
+ servingSerialNumber, request);
+ }
+
+ void cancelRequest(NetworkRequest request) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request);
+ }
+
+ void connect(Context context, Handler handler) {
+ mAsyncChannel.connect(context, handler, messenger);
+ }
+
+ void completeConnection() {
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ }
}
private void ensureNetworkRequestHasType(NetworkRequest request) {
@@ -5325,7 +5325,7 @@
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
- nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
+ nfi.connect(mContext, mTrackerHandler);
}
@Override
@@ -5961,8 +5961,26 @@
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
- serial, networkRequest);
+ nfi.requestNetwork(networkRequest, score, serial);
+ }
+ }
+
+ /** Sends all current NetworkRequests to the specified factory. */
+ private void sendAllRequestsToFactory(NetworkFactoryInfo nfi) {
+ ensureRunningOnConnectivityServiceThread();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.request.isListen()) continue;
+ NetworkAgentInfo nai = nri.mSatisfier;
+ final int score;
+ final int serial;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkFactory.SerialNumber.NONE;
+ }
+ nfi.requestNetwork(nri.request, score, serial);
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c5f1923..0fc5340 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -3192,6 +3192,8 @@
}
ipw.decreaseIndent();
+ mRequestStatistics.history.dump(ipw);
+
ipw.println("Last Known Locations:");
ipw.increaseIndent();
for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index cfe56052..d20936c 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -36,11 +36,11 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TimeUtils;
-import android.util.TimestampedValue;
import com.android.internal.util.DumpUtils;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a4c44fa..d7ad1c2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2934,33 +2934,37 @@
}
ArraySet<Long> enabled = new ArraySet<>();
ArraySet<Long> disabled = new ArraySet<>();
- switch (toggleValue) {
- case "enable":
- enabled.add(changeId);
- pw.println("Enabled change " + changeId + " for " + packageName + ".");
- CompatibilityChangeConfig overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "disable":
- disabled.add(changeId);
- pw.println("Disabled change " + changeId + " for " + packageName + ".");
- overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "reset":
- if (platformCompat.clearOverride(changeId, packageName)) {
- pw.println("Reset change " + changeId + " for " + packageName
- + " to default value.");
- } else {
- pw.println("No override exists for changeId " + changeId + ".");
- }
- return 0;
- default:
- pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ try {
+ switch (toggleValue) {
+ case "enable":
+ enabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "disable":
+ disabled.add(changeId);
+ overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "reset":
+ if (platformCompat.clearOverride(changeId, packageName)) {
+ pw.println("Reset change " + changeId + " for " + packageName
+ + " to default value.");
+ } else {
+ pw.println("No override exists for changeId " + changeId + ".");
+ }
+ return 0;
+ default:
+ pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ }
+ } catch (SecurityException e) {
+ pw.println(e.getMessage());
}
return -1;
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index cf83dd6..f15d999 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,8 +17,10 @@
package com.android.server.compat;
import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Environment;
+import android.os.RemoteException;
import android.text.TextUtils;
import android.util.LongArray;
import android.util.LongSparseArray;
@@ -26,8 +28,11 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.config.XmlParser;
@@ -54,22 +59,14 @@
private static final String TAG = "CompatConfig";
- private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
- Environment.buildPath(
- Environment.getRootDirectory(), "etc", "compatconfig"));
-
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
- @VisibleForTesting
- CompatConfig() {
- }
+ private IOverrideValidator mOverrideValidator;
- /**
- * @return The static instance of this class to be used within the system server.
- */
- static CompatConfig get() {
- return sInstance;
+ @VisibleForTesting
+ CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
}
/**
@@ -159,8 +156,12 @@
* @param enabled If the change should be enabled or disabled.
* @return {@code true} if the change existed before adding the override.
*/
- boolean addOverride(long changeId, String packageName, boolean enabled) {
+ boolean addOverride(long changeId, String packageName, boolean enabled)
+ throws RemoteException, SecurityException {
boolean alreadyKnown = true;
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c == null) {
@@ -186,6 +187,20 @@
}
/**
+ * Returns the minimum sdk version for which this change should be enabled (or 0 if it is not
+ * target sdk gated).
+ */
+ int minTargetSdkForChangeId(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return 0;
+ }
+ return c.getEnableAfterTargetSdk();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
* restores the default behaviour for the given change and app, once any app processes have been
* restarted.
@@ -194,34 +209,44 @@
* @param packageName The app package name that was overridden.
* @return {@code true} if an override existed;
*/
- boolean removeOverride(long changeId, String packageName) {
+ boolean removeOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c != null) {
- overrideExists = true;
- c.removePackageOverride(packageName);
+ try {
+ if (c != null) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
+ overrideExists = true;
+ c.removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
}
}
return overrideExists;
}
/**
- * Overrides the enabled state for a given change and app. This method is intended to be used
- * *only* for debugging purposes.
+ * Overrides the enabled state for a given change and app.
*
* <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
*
* @param overrides list of overrides to default changes config.
* @param packageName app for which the overrides will be applied.
*/
- void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
+ void addOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
synchronized (mChanges) {
for (Long changeId : overrides.enabledChanges()) {
addOverride(changeId, packageName, true);
}
for (Long changeId : overrides.disabledChanges()) {
addOverride(changeId, packageName, false);
+
}
}
}
@@ -235,10 +260,22 @@
*
* @param packageName The package for which the overrides should be purged.
*/
- void removePackageOverrides(String packageName) {
+ void removePackageOverrides(String packageName) throws RemoteException, SecurityException {
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
- mChanges.valueAt(i).removePackageOverride(packageName);
+ try {
+ CompatChange change = mChanges.valueAt(i);
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ allowedState.enforce(change.getId(), packageName);
+ if (change != null) {
+ mChanges.valueAt(i).removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
+ }
}
}
}
@@ -326,17 +363,23 @@
}
}
- CompatConfig initConfigFromLib(File libraryDir) {
+ static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ CompatConfig config = new CompatConfig(androidBuildClassifier, context);
+ config.initConfigFromLib(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "compatconfig"));
+ return config;
+ }
+
+ void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.e(TAG, "No directory " + libraryDir + ", skipping");
- return this;
+ return;
}
for (File f : libraryDir.listFiles()) {
Slog.d(TAG, "Found a config file: " + f.getPath());
//TODO(b/138222363): Handle duplicate ids across config files.
readConfig(f);
}
- return this;
}
private void readConfig(File configFile) {
@@ -350,4 +393,7 @@
}
}
+ IOverrideValidator getOverrideValidator() {
+ return mOverrideValidator;
+ }
}
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
new file mode 100644
index 0000000..dfc0080
--- /dev/null
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -0,0 +1,94 @@
+/*
+ * 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.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Implementation of the policy for allowing compat change overrides.
+ */
+public class OverrideValidatorImpl extends IOverrideValidator.Stub {
+
+ private AndroidBuildClassifier mAndroidBuildClassifier;
+ private Context mContext;
+ private CompatConfig mCompatConfig;
+
+ @VisibleForTesting
+ OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier,
+ Context context, CompatConfig config) {
+ mAndroidBuildClassifier = androidBuildClassifier;
+ mContext = context;
+ mCompatConfig = config;
+ }
+
+ @Override
+ public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
+ boolean debuggableBuild = false;
+ boolean finalBuild = false;
+
+ debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+ finalBuild = mAndroidBuildClassifier.isFinalBuild();
+
+ // Allow any override for userdebug or eng builds.
+ if (debuggableBuild) {
+ return new OverrideAllowedState(ALLOWED, -1, -1);
+ }
+ PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager == null) {
+ throw new IllegalStateException("No PackageManager!");
+ }
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1);
+ }
+ int appTargetSdk = applicationInfo.targetSdkVersion;
+ // Only allow overriding debuggable apps.
+ if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1);
+ }
+ int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+ // Do not allow overriding non-target sdk gated changes on user builds
+ if (minTargetSdk == -1) {
+ return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
+ }
+ // Allow overriding any change for debuggable apps on non-final builds.
+ if (!finalBuild) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ // Only allow to opt-in for a targetSdk gated change.
+ if (applicationInfo.targetSdkVersion < minTargetSdk) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
+ }
+}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6ec4b9f..bb8b12e 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -27,9 +27,12 @@
import android.util.Slog;
import android.util.StatsLog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.ChangeReporter;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
@@ -46,11 +49,21 @@
private final Context mContext;
private final ChangeReporter mChangeReporter;
+ private final CompatConfig mCompatConfig;
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+ }
+
+ @VisibleForTesting
+ PlatformCompat(Context context, CompatConfig compatConfig) {
+ mContext = context;
+ mChangeReporter = new ChangeReporter(
+ StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = compatConfig;
}
@Override
@@ -75,7 +88,7 @@
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
+ if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
return true;
@@ -122,57 +135,59 @@
* otherwise.
*/
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
- return CompatConfig.get().registerListener(changeId, listener);
+ return mCompatConfig.registerListener(changeId, listener);
}
@Override
- public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@Override
- public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
}
@Override
- public void clearOverrides(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@Override
- public void clearOverridesForTest(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverridesForTest(String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
}
@Override
- public boolean clearOverride(long changeId, String packageName) {
- boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
+ public boolean clearOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
+ boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
}
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- return CompatConfig.get().getAppConfig(appInfo);
+ return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
- return CompatConfig.get().dumpChanges();
+ return mCompatConfig.dumpChanges();
}
/**
* Check whether the change is known to the compat config.
- * @param changeId
+ *
* @return {@code true} if the change is known.
*/
public boolean isKnownChangeId(long changeId) {
- return CompatConfig.get().isKnownChangeId(changeId);
+ return mCompatConfig.isKnownChangeId(changeId);
}
@@ -182,11 +197,11 @@
*
* @param appInfo The app in question
* @return A sorted long array of change IDs. We use a primitive array to minimize memory
- * footprint: Every app process will store this array statically so we aim to reduce
- * overhead as much as possible.
+ * footprint: Every app process will store this array statically so we aim to reduce
+ * overhead as much as possible.
*/
public long[] getDisabledChanges(ApplicationInfo appInfo) {
- return CompatConfig.get().getDisabledChanges(appInfo);
+ return mCompatConfig.getDisabledChanges(appInfo);
}
/**
@@ -196,18 +211,24 @@
* @return The change ID, or {@code -1} if no change with that name exists.
*/
public long lookupChangeId(String name) {
- return CompatConfig.get().lookupChangeId(name);
+ return mCompatConfig.lookupChangeId(name);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
- CompatConfig.get().dumpConfig(pw);
+ mCompatConfig.dumpConfig(pw);
+ }
+
+ @Override
+ public IOverrideValidator getOverrideValidator() {
+ return mCompatConfig.getOverrideValidator();
}
/**
* Clears information stored about events reported on behalf of an app.
* To be called once upon app start or end. A second call would be a no-op.
+ *
* @param appInfo the app to reset
*/
public void resetReporting(ApplicationInfo appInfo) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e39d6d5..d7ae5b5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1305,13 +1305,21 @@
}
private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) {
- final IBinder token = getDisplayToken(displayId);
- if (token == null) {
- return null;
+ synchronized (mSyncRoot) {
+ final IBinder token = getDisplayToken(displayId);
+ if (token == null) {
+ return null;
+ }
+ final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId);
+ if (logicalDisplay == null) {
+ return null;
+ }
+
+ final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
+ return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(),
+ displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(),
+ false /* useIdentityTransform */, 0 /* rotation */);
}
- return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
- token, new Rect(), 0 /* width */, 0 /* height */,
- false /* useIdentityTransform */, 0 /* rotation */);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
index f90fab4..31d4816 100644
--- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java
+++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.integrity.parser.RuleBinaryParser;
+import com.android.server.integrity.parser.RuleIndexRange;
import com.android.server.integrity.parser.RuleIndexingController;
import com.android.server.integrity.parser.RuleMetadataParser;
import com.android.server.integrity.parser.RuleParseException;
@@ -152,7 +153,7 @@
throws IOException, RuleParseException {
synchronized (RULES_LOCK) {
// Try to identify indexes from the index file.
- List<List<Integer>> ruleReadingIndexes =
+ List<RuleIndexRange> ruleReadingIndexes =
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
// Read the rules based on the index information.
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
new file mode 100644
index 0000000..8c8450e
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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.server.integrity.parser;
+
+import android.annotation.Nullable;
+
+/**
+ * A wrapper class to represent an indexing range that is identified by the {@link
+ * RuleIndexingController}.
+ */
+public class RuleIndexRange {
+ private static int sStartIndex;
+ private static int sEndIndex;
+
+ /** Constructor with start and end indexes. */
+ public RuleIndexRange(int startIndex, int endIndex) {
+ this.sStartIndex = startIndex;
+ this.sEndIndex = endIndex;
+ }
+
+ /** Returns the startIndex. */
+ public int getStartIndex() {
+ return sStartIndex;
+ }
+
+ /** Returns the end index. */
+ public int getEndIndex() {
+ return sEndIndex;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ return sStartIndex == ((RuleIndexRange) object).getStartIndex()
+ && sEndIndex == ((RuleIndexRange) object).getEndIndex();
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index b642fa6..c971322 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -17,6 +17,7 @@
package com.android.server.integrity.parser;
import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;
@@ -24,25 +25,27 @@
import com.android.server.integrity.model.BitInputStream;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
-import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
/** Helper class to identify the necessary indexes that needs to be read. */
public class RuleIndexingController {
- private static TreeMap<String, Integer> sPackageNameBasedIndexes;
- private static TreeMap<String, Integer> sAppCertificateBasedIndexes;
- private static TreeMap<String, Integer> sUnindexedRuleIndexes;
+ private static LinkedHashMap<String, Integer> sPackageNameBasedIndexes;
+ private static LinkedHashMap<String, Integer> sAppCertificateBasedIndexes;
+ private static LinkedHashMap<String, Integer> sUnindexedRuleIndexes;
/**
* Provide the indexing file to read and the object will be constructed by reading and
* identifying the indexes.
*/
- public RuleIndexingController(FileInputStream fileInputStream) throws IOException {
- BitInputStream bitInputStream = new BitInputStream(fileInputStream);
+ public RuleIndexingController(InputStream inputStream) throws IOException {
+ BitInputStream bitInputStream = new BitInputStream(inputStream);
sPackageNameBasedIndexes = getNextIndexGroup(bitInputStream);
sAppCertificateBasedIndexes = getNextIndexGroup(bitInputStream);
sUnindexedRuleIndexes = getNextIndexGroup(bitInputStream);
@@ -52,24 +55,57 @@
* Returns a list of integers with the starting and ending bytes of the rules that needs to be
* read and evaluated.
*/
- public List<List<Integer>> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
- // TODO(b/145493956): Identify and return the indexes that needs to be read.
- return new ArrayList<>();
+ public List<RuleIndexRange> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
+ ArrayList<RuleIndexRange> indexRanges = new ArrayList();
+
+ // Add the range for package name indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sPackageNameBasedIndexes, appInstallMetadata.getPackageName()));
+
+ // Add the range for app certificate indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sAppCertificateBasedIndexes, appInstallMetadata.getAppCertificate()));
+
+ // Add the range for unindexed rules.
+ indexRanges.add(
+ new RuleIndexRange(
+ sUnindexedRuleIndexes.get(START_INDEXING_KEY),
+ sUnindexedRuleIndexes.get(END_INDEXING_KEY)));
+
+ return indexRanges;
}
- private TreeMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
+ private LinkedHashMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
throws IOException {
- TreeMap<String, Integer> keyToIndexMap = new TreeMap<>();
+ LinkedHashMap<String, Integer> keyToIndexMap = new LinkedHashMap<>();
while (bitInputStream.hasNext()) {
String key = getStringValue(bitInputStream);
int value = getIntValue(bitInputStream);
keyToIndexMap.put(key, value);
- if (key == END_INDEXING_KEY) {
+ if (key.matches(END_INDEXING_KEY)) {
break;
}
}
return keyToIndexMap;
}
+
+ private RuleIndexRange searchIndexingKeysRangeContainingKey(
+ LinkedHashMap<String, Integer> indexMap, String searchedKey) {
+ TreeSet<String> keyTreeSet =
+ indexMap.keySet().stream()
+ .filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
+ END_INDEXING_KEY))
+ .collect(Collectors.toCollection(TreeSet::new));
+
+ String minIndex = keyTreeSet.floor(searchedKey);
+ String maxIndex = keyTreeSet.ceiling(searchedKey);
+
+ return new RuleIndexRange(
+ indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
+ indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
+ }
}
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7ccb26..45c8334 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -1,8 +1,29 @@
+/*
+ * Copyright 2020 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.server.location;
import android.os.SystemClock;
import android.util.Log;
+import android.util.TimeUtils;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -17,6 +38,8 @@
public final HashMap<PackageProviderKey, PackageStatistics> statistics
= new HashMap<PackageProviderKey, PackageStatistics>();
+ public final RequestSummaryLimitedHistory history = new RequestSummaryLimitedHistory();
+
/**
* Signals that a package has started requesting locations.
*
@@ -34,6 +57,7 @@
}
stats.startRequesting(intervalMs);
stats.updateForeground(isForeground);
+ history.addRequest(packageName, providerName, intervalMs);
}
/**
@@ -48,6 +72,7 @@
if (stats != null) {
stats.stopRequesting();
}
+ history.removeRequest(packageName, providerName);
}
/**
@@ -77,7 +102,7 @@
*/
public final String providerName;
- public PackageProviderKey(String packageName, String providerName) {
+ PackageProviderKey(String packageName, String providerName) {
this.packageName = packageName;
this.providerName = providerName;
}
@@ -100,6 +125,104 @@
}
/**
+ * A data structure to hold past requests
+ */
+ public static class RequestSummaryLimitedHistory {
+ @VisibleForTesting
+ static final int MAX_SIZE = 100;
+
+ final ArrayList<RequestSummary> mList = new ArrayList<>(MAX_SIZE);
+
+ /**
+ * Append an added location request to the history
+ */
+ @VisibleForTesting
+ void addRequest(String packageName, String providerName, long intervalMs) {
+ addRequestSummary(new RequestSummary(packageName, providerName, intervalMs));
+ }
+
+ /**
+ * Append a removed location request to the history
+ */
+ @VisibleForTesting
+ void removeRequest(String packageName, String providerName) {
+ addRequestSummary(new RequestSummary(
+ packageName, providerName, RequestSummary.REQUEST_ENDED_INTERVAL));
+ }
+
+ private void addRequestSummary(RequestSummary summary) {
+ while (mList.size() >= MAX_SIZE) {
+ mList.remove(0);
+ }
+ mList.add(summary);
+ }
+
+ /**
+ * Dump history to a printwriter (for dumpsys location)
+ */
+ public void dump(IndentingPrintWriter ipw) {
+ long systemElapsedOffsetMillis = System.currentTimeMillis()
+ - SystemClock.elapsedRealtime();
+
+ ipw.println("Last Several Location Requests:");
+ ipw.increaseIndent();
+
+ for (RequestSummary requestSummary : mList) {
+ requestSummary.dump(ipw, systemElapsedOffsetMillis);
+ }
+
+ ipw.decreaseIndent();
+ }
+ }
+
+ /**
+ * A data structure to hold a single request
+ */
+ static class RequestSummary {
+ /**
+ * Name of package requesting location.
+ */
+ private final String mPackageName;
+ /**
+ * Name of provider being requested (e.g. "gps").
+ */
+ private final String mProviderName;
+ /**
+ * Interval Requested, or REQUEST_ENDED_INTERVAL indicating request has ended
+ */
+ private final long mIntervalMillis;
+ /**
+ * Elapsed time of request
+ */
+ private final long mElapsedRealtimeMillis;
+
+ /**
+ * Placeholder for requested ending (other values indicate request started/changed)
+ */
+ static final long REQUEST_ENDED_INTERVAL = -1;
+
+ RequestSummary(String packageName, String providerName, long intervalMillis) {
+ this.mPackageName = packageName;
+ this.mProviderName = providerName;
+ this.mIntervalMillis = intervalMillis;
+ this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
+ }
+
+ void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
+ StringBuilder s = new StringBuilder();
+ long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
+ s.append("At ").append(TimeUtils.formatForLogging(systemTimeMillis)).append(": ")
+ .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
+ .append(String.format("%7s", mProviderName)).append(" request from ")
+ .append(mPackageName);
+ if (mIntervalMillis != REQUEST_ENDED_INTERVAL) {
+ s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds");
+ }
+ ipw.println(s);
+ }
+ }
+
+ /**
* Usage statistics for a package/provider pair.
*/
public static class PackageStatistics {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e04d10c..956962e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -562,10 +562,6 @@
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
- private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
- private volatile boolean mMovingDisplayToTopKeyTriggered;
- private volatile long mMovingDisplayToTopKeyTime;
-
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -633,7 +629,6 @@
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
private static final int MSG_RINGER_TOGGLE_CHORD = 27;
- private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
private class PolicyHandler extends Handler {
@Override
@@ -723,10 +718,6 @@
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
- case MSG_MOVE_DISPLAY_TO_TOP:
- mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
- mMovingDisplayToTopKeyTriggered = false;
- break;
}
}
}
@@ -2545,36 +2536,6 @@
@Override
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
int policyFlags) {
- final long result = interceptKeyBeforeDispatchingInner(focusedToken, event, policyFlags);
- final int eventDisplayId = event.getDisplayId();
- if (result == 0 && !mPerDisplayFocusEnabled
- && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
- // An event is targeting a non-focused display. Try to move the display to top so that
- // it can become the focused display to interact with the user.
- final long eventDownTime = event.getDownTime();
- if (mMovingDisplayToTopKeyTime < eventDownTime) {
- // We have not handled this event yet. Move the display to top, and then tell
- // dispatcher to try again later.
- mMovingDisplayToTopKeyTime = eventDownTime;
- mMovingDisplayToTopKeyTriggered = true;
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- } else if (mMovingDisplayToTopKeyTriggered) {
- // The message has not been handled yet. Tell dispatcher to try again later.
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- }
- // The target display is still not the top focused display. Drop the event because the
- // display may not contain any window which can receive keys.
- Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
- + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
- return -1;
- }
- return result;
- }
-
- private long interceptKeyBeforeDispatchingInner(IBinder focusedToken, KeyEvent event,
- int policyFlags) {
final boolean keyguardOn = keyguardOn();
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
@@ -3615,7 +3576,6 @@
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
final int displayId = event.getDisplayId();
-
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
// If screen is off then we treat the case where the keyguard is open but hidden
@@ -4037,6 +3997,23 @@
PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
}
+ if ((result & ACTION_PASS_TO_USER) != 0) {
+ // If the key event is targeted to a specific display, then the user is interacting with
+ // that display. Therefore, give focus to the display that the user is interacting with.
+ if (!mPerDisplayFocusEnabled
+ && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
+ // An event is targeting a non-focused display. Move the display to top so that
+ // it can become the focused display to interact with the user.
+ // This should be done asynchronously, once the focus logic is fully moved to input
+ // from windowmanager. Currently, we need to ensure the setInputWindows completes,
+ // which would force the focus event to be queued before the current key event.
+ // TODO(b/70668286): post call to 'moveDisplayToTop' to mHandler instead
+ Log.i(TAG, "Moving non-focused display " + displayId + " to top "
+ + "because a key is targeting it");
+ mWindowManagerFuncs.moveDisplayToTop(displayId);
+ }
+ }
+
return result;
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index b4f4eca..f661b5e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -22,7 +22,7 @@
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 02656ea..da848d8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -24,10 +24,10 @@
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
+import android.os.TimestampedValue;
import android.telephony.TelephonyManager;
import android.util.LocalLog;
import android.util.Slog;
-import android.util.TimestampedValue;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 65d0c4c..e281712 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6107,11 +6107,6 @@
// This also avoids if the next activity never reports idle (e.g. animating view),
// the previous will need to wait until idle timeout to be stopped or destroyed.
mStackSupervisor.scheduleProcessStoppingAndFinishingActivities();
- } else {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
- true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
}
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e8564fc..fd871bd 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2076,54 +2076,11 @@
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
- processStoppingActivities(launchedActivity, false /* onlyUpdateVisibility */,
- processPausingActivities, reason);
-
- final int numFinishingActivities = mFinishingActivities.size();
- if (numFinishingActivities == 0) {
- return;
- }
-
- // Finish any activities that are scheduled to do so but have been waiting for the next one
- // to start.
- final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
- mFinishingActivities.clear();
- for (int i = 0; i < numFinishingActivities; i++) {
- final ActivityRecord r = finishingActivities.get(i);
- if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
- }
- }
- }
-
- /** Stop or destroy the stopping activities if they are not interactive. */
- void processStoppingActivities(ActivityRecord launchedActivity, boolean onlyUpdateVisibility,
- boolean processPausingActivities, String reason) {
- final int numStoppingActivities = mStoppingActivities.size();
- if (numStoppingActivities == 0) {
- return;
- }
ArrayList<ActivityRecord> readyToStopActivities = null;
-
- final boolean nowVisible = mRootWindowContainer.allResumedActivitiesVisible();
- for (int activityNdx = numStoppingActivities - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord s = mStoppingActivities.get(activityNdx);
- if (nowVisible && s.finishing) {
-
- // If this activity is finishing, it is sitting on top of
- // everyone else but we now know it is no longer needed...
- // so get rid of it. Otherwise, we need to go through the
- // normal flow and hide it once we determine that it is
- // hidden by the activities in front of it.
- if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
- s.setVisibility(false);
- }
- if (onlyUpdateVisibility) {
- continue;
- }
-
+ for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord s = mStoppingActivities.get(i);
final boolean animating = s.isAnimating(TRANSITION);
- if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+ if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible
+ " animating=" + animating + " finishing=" + s.finishing);
final ActivityStack stack = s.getActivityStack();
@@ -2145,7 +2102,7 @@
}
readyToStopActivities.add(s);
- mStoppingActivities.remove(activityNdx);
+ mStoppingActivities.remove(i);
}
}
@@ -2161,6 +2118,22 @@
}
}
}
+
+ final int numFinishingActivities = mFinishingActivities.size();
+ if (numFinishingActivities == 0) {
+ return;
+ }
+
+ // Finish any activities that are scheduled to do so but have been waiting for the next one
+ // to start.
+ final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
+ mFinishingActivities.clear();
+ for (int i = 0; i < numFinishingActivities; i++) {
+ final ActivityRecord r = finishingActivities.get(i);
+ if (r.isInHistory()) {
+ r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ }
+ }
}
void removeHistoryRecords(WindowProcessController app) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7f94445..ba9d757 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -205,6 +205,7 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindow;
import android.view.InputChannel;
@@ -218,6 +219,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -570,6 +572,8 @@
*/
WindowState mInputMethodTarget;
+ InsetsControlTarget mInputMethodControlTarget;
+
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
@@ -598,6 +602,13 @@
private final float mWindowCornerRadius;
private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+ RemoteInsetsControlTarget mRemoteInsetsControlTarget = null;
+ private final IBinder.DeathRecipient mRemoteInsetsDeath =
+ () -> {
+ synchronized (mWmService.mGlobalLock) {
+ mRemoteInsetsControlTarget = null;
+ }
+ };
private RootWindowContainer mRootWindowContainer;
@@ -772,7 +783,11 @@
// If this is the first layout, we need to initialize the last frames and inset values,
// as otherwise we'd immediately cause an unnecessary resize.
if (firstLayout) {
- w.updateLastFrames();
+ // The client may compute its actual requested size according to the first layout,
+ // so we still request the window to resize if the current frame is empty.
+ if (!w.getFrameLw().isEmpty()) {
+ w.updateLastFrames();
+ }
w.updateLastInsetValues();
w.updateLocationInParentDisplayIfNeeded();
}
@@ -1152,6 +1167,22 @@
mShellRoots.remove(windowType);
}
+ void setRemoteInsetsController(IDisplayWindowInsetsController controller) {
+ if (mRemoteInsetsControlTarget != null) {
+ mRemoteInsetsControlTarget.mRemoteInsetsController.asBinder().unlinkToDeath(
+ mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = null;
+ }
+ if (controller != null) {
+ try {
+ controller.asBinder().linkToDeath(mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = new RemoteInsetsControlTarget(controller);
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+ }
+
/** Changes the display the input window token is housed on to this one. */
void reParentWindowToken(WindowToken token) {
final DisplayContent prevDc = token.getDisplayContent();
@@ -3379,6 +3410,14 @@
}
}
+ boolean isImeAttachedToApp() {
+ return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
+ && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ // An activity with override bounds should be letterboxed inside its parent bounds,
+ // so it doesn't fill the screen.
+ && mInputMethodTarget.mActivityRecord.matchParentBounds());
+ }
+
private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) {
if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) {
return;
@@ -3387,7 +3426,8 @@
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
assignWindowLayers(false /* setLayoutNeeded */);
- mInsetsStateController.onImeTargetChanged(target);
+ mInputMethodControlTarget = computeImeControlTarget();
+ mInsetsStateController.onImeTargetChanged(mInputMethodControlTarget);
updateImeParent();
}
@@ -3412,11 +3452,7 @@
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
- if (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
- && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- // An activity with override bounds should be letterboxed inside its parent bounds,
- // so it doesn't fill the screen.
- && mInputMethodTarget.mActivityRecord.matchParentBounds()) {
+ if (isImeAttachedToApp()) {
return mInputMethodTarget.mActivityRecord.getSurfaceControl();
}
@@ -3424,6 +3460,19 @@
return mWindowContainers.getSurfaceControl();
}
+ /**
+ * Computes which control-target the IME should be attached to.
+ */
+ @VisibleForTesting
+ InsetsControlTarget computeImeControlTarget() {
+ if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
+ return mRemoteInsetsControlTarget;
+ }
+
+ // Otherwise, we just use the ime target
+ return mInputMethodTarget;
+ }
+
void setLayoutNeeded() {
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
mLayoutNeeded = true;
@@ -6684,4 +6733,50 @@
Context getDisplayUiContext() {
return mDisplayPolicy.getSystemUiContext();
}
+
+ class RemoteInsetsControlTarget implements InsetsControlTarget {
+ private final IDisplayWindowInsetsController mRemoteInsetsController;
+
+ RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
+ mRemoteInsetsController = controller;
+ }
+
+ void notifyInsetsChanged() {
+ try {
+ mRemoteInsetsController.insetsChanged(
+ getInsetsStateController().getRawInsetsState());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void notifyInsetsControlChanged() {
+ final InsetsStateController stateController = getInsetsStateController();
+ try {
+ mRemoteInsetsController.insetsControlChanged(stateController.getRawInsetsState(),
+ stateController.getControlsForDispatch(this));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.showInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+
+ @Override
+ public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.hideInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 05ede21..fb97ecf 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -69,7 +69,7 @@
mShowImeRunner = () -> {
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
- mDisplayContent.mInputMethodTarget.showInsets(
+ mDisplayContent.mInputMethodControlTarget.showInsets(
WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 184e7d6..7b40f60 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -210,7 +210,7 @@
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
}
- boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
+ boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) {
if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 1526074..720493f 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -91,6 +91,10 @@
return state;
}
+ InsetsState getRawInsetsState() {
+ return mState;
+ }
+
@Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
if (controlled == null) {
@@ -144,7 +148,7 @@
getImeSourceProvider().onPostInsetsDispatched();
}
- void onInsetsModified(WindowState windowState, InsetsState state) {
+ void onInsetsModified(InsetsControlTarget windowState, InsetsState state) {
boolean changed = false;
for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
@@ -296,6 +300,9 @@
void notifyInsetsChanged() {
mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
+ if (mDisplayContent.mRemoteInsetsControlTarget != null) {
+ mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
+ }
}
void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 399c5d3..eaa0ea7 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,8 +16,12 @@
package com.android.server.wm;
+import static com.android.server.wm.AnimationSpecProto.ROTATE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS;
+import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA;
+import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA;
import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -25,7 +29,9 @@
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
+import android.animation.ArgbEvaluator;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -40,7 +46,9 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import com.android.internal.R;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.utils.RotationAnimationUtils;
import java.io.PrintWriter;
@@ -60,10 +68,10 @@
* animation first rotate the new content into the old orientation to then be able to
* animate to the new orientation
*
- * <li> The exiting Blackframe: <p>
- * Because the change of orientation might change the width and height of the content (i.e
- * when rotating from portrait to landscape) we "crop" the new content using black frames
- * around the screenshot so the new content does not go beyond the screenshot's bounds
+ * <li> The Background color frame: <p>
+ * To have the animation seem more seamless, we add a color transitioning background behind the
+ * exiting and entering layouts. We compute the brightness of the start and end
+ * layouts and transition from the two brightness values as grayscale underneath the animation
*
* <li> The entering Blackframe: <p>
* The enter Blackframe is similar to the exit Blackframe but is only used when a custom
@@ -81,8 +89,6 @@
*/
private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
- private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
- private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
private final Context mContext;
private final DisplayContent mDisplayContent;
@@ -90,16 +96,18 @@
private final Transformation mRotateExitTransformation = new Transformation();
private final Transformation mRotateEnterTransformation = new Transformation();
// Complete transformations being applied.
- private final Transformation mExitTransformation = new Transformation();
private final Transformation mEnterTransformation = new Transformation();
- private final Matrix mFrameInitialMatrix = new Matrix();
private final Matrix mSnapshotInitialMatrix = new Matrix();
- private final Matrix mSnapshotFinalMatrix = new Matrix();
- private final Matrix mExitFrameFinalMatrix = new Matrix();
private final WindowManagerService mService;
+ /** Only used for custom animations and not screen rotation. */
private SurfaceControl mEnterBlackFrameLayer;
- private SurfaceControl mRotationLayer;
- private SurfaceControl mSurfaceControl;
+ /** This layer contains the actual screenshot that is to be faded out. */
+ private SurfaceControl mScreenshotLayer;
+ /**
+ * Only used for screen rotation and not custom animations. Layered behind all other layers
+ * to avoid showing any "empty" spots
+ */
+ private SurfaceControl mBackColorSurface;
private BlackFrame mEnteringBlackFrame;
private int mWidth, mHeight;
@@ -120,8 +128,11 @@
private boolean mFinishAnimReady;
private long mFinishAnimStartTime;
private boolean mForceDefaultOrientation;
- private BlackFrame mExitingBlackFrame;
private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
+ /** Intensity of light/whiteness of the layout before rotation occurs. */
+ private float mStartLuma;
+ /** Intensity of light/whiteness of the layout after rotation occurs. */
+ private float mEndLuma;
public ScreenRotationAnimation(Context context, DisplayContent displayContent,
boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -162,9 +173,15 @@
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
- mRotationLayer = displayContent.makeOverlay()
+ mBackColorSurface = displayContent.makeChildSurface(null)
+ .setName("BackColorSurface")
+ .setColorLayer()
+ .build();
+
+ mScreenshotLayer = displayContent.makeOverlay()
.setName("RotationLayer")
- .setContainerLayer()
+ .setBufferSize(mWidth, mHeight)
+ .setSecure(isSecure)
.build();
mEnterBlackFrameLayer = displayContent.makeOverlay()
@@ -172,26 +189,21 @@
.setContainerLayer()
.build();
- mSurfaceControl = mService.makeSurfaceBuilder(null)
- .setName("ScreenshotSurface")
- .setParent(mRotationLayer)
- .setBufferSize(mWidth, mHeight)
- .setSecure(isSecure)
- .build();
-
// In case display bounds change, screenshot buffer and surface may mismatch so set a
// scaling mode.
SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
- t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+ t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
t2.apply(true /* sync */);
// Capture a screenshot into the surface we just created.
final int displayId = display.getDisplayId();
final Surface surface = mService.mSurfaceFactory.get();
- surface.copyFrom(mSurfaceControl);
+ surface.copyFrom(mScreenshotLayer);
SurfaceControl.ScreenshotGraphicBuffer gb =
mService.mDisplayManagerInternal.screenshot(displayId);
if (gb != null) {
+ mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(),
+ gb.getColorSpace());
try {
surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
gb.getColorSpace());
@@ -202,13 +214,15 @@
// screenshot surface we display it in also has FLAG_SECURE so that
// the user can not screenshot secure layers via the screenshot surface.
if (gb.containsSecureLayers()) {
- t.setSecure(mSurfaceControl, true);
+ t.setSecure(mScreenshotLayer, true);
}
- t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
- t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
- t.setAlpha(mSurfaceControl, 0);
- t.show(mRotationLayer);
- t.show(mSurfaceControl);
+ t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
+ t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
+ t.setLayer(mBackColorSurface, -1);
+ t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
+ t.setAlpha(mBackColorSurface, 1);
+ t.show(mScreenshotLayer);
+ t.show(mBackColorSurface);
} else {
Slog.w(TAG, "Unable to take screenshot of display " + displayId);
}
@@ -218,32 +232,11 @@
}
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
- " FREEZE %s: CREATE", mSurfaceControl);
+ " FREEZE %s: CREATE", mScreenshotLayer);
setRotation(t, originalRotation);
t.apply();
}
- private static void createRotationMatrix(int rotation, int width, int height,
- Matrix outMatrix) {
- switch (rotation) {
- case Surface.ROTATION_0:
- outMatrix.reset();
- break;
- case Surface.ROTATION_90:
- outMatrix.setRotate(90, 0, 0);
- outMatrix.postTranslate(height, 0);
- break;
- case Surface.ROTATION_180:
- outMatrix.setRotate(180, 0, 0);
- outMatrix.postTranslate(width, height);
- break;
- case Surface.ROTATION_270:
- outMatrix.setRotate(270, 0, 0);
- outMatrix.postTranslate(0, width);
- break;
- }
- }
-
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(STARTED, mStarted);
@@ -252,11 +245,11 @@
}
boolean hasScreenshot() {
- return mSurfaceControl != null;
+ return mScreenshotLayer != null;
}
private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
- if (mRotationLayer == null) {
+ if (mScreenshotLayer == null) {
return;
}
matrix.getValues(mTmpFloats);
@@ -267,24 +260,19 @@
x -= mCurrentDisplayRect.left;
y -= mCurrentDisplayRect.top;
}
- t.setPosition(mRotationLayer, x, y);
- t.setMatrix(mRotationLayer,
+ t.setPosition(mScreenshotLayer, x, y);
+ t.setMatrix(mScreenshotLayer,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- t.setAlpha(mSurfaceControl, (float) 1.0);
- t.setAlpha(mRotationLayer, (float) 1.0);
- t.show(mRotationLayer);
+ t.setAlpha(mScreenshotLayer, (float) 1.0);
+ t.show(mScreenshotLayer);
}
public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
+ pw.print(prefix); pw.print("mSurface="); pw.print(mScreenshotLayer);
pw.print(" mWidth="); pw.print(mWidth);
pw.print(" mHeight="); pw.println(mHeight);
- pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.printTo(prefix + " ", pw);
- }
pw.print(prefix);
pw.print("mEnteringBlackFrame=");
pw.println(mEnteringBlackFrame);
@@ -303,20 +291,10 @@
pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mExitTransformation=");
- mExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mEnterTransformation=");
mEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mFrameInitialMatrix=");
- mFrameInitialMatrix.printShortString(pw);
- pw.println();
pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
- mSnapshotInitialMatrix.printShortString(pw);
- pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
- pw.println();
- pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
- mExitFrameFinalMatrix.printShortString(pw);
- pw.println();
+ mSnapshotInitialMatrix.printShortString(pw);pw.println();
pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
if (mForceDefaultOrientation) {
pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
@@ -331,7 +309,7 @@
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
- createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
+ RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
setRotationTransform(t, mSnapshotInitialMatrix);
}
@@ -341,7 +319,7 @@
*/
private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
@@ -354,89 +332,58 @@
// Figure out how the screen has moved from the original rotation.
int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
- mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_alpha);
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
customAnim = true;
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
+ mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
+ R.anim.screen_rotate_alpha);
} else {
customAnim = false;
- switch (delta) {
+ switch (delta) { /* Counter-Clockwise Rotations */
case Surface.ROTATION_0:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_exit);
+ R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_enter);
+ R.anim.screen_rotate_0_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_exit);
+ R.anim.screen_rotate_plus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_enter);
+ R.anim.screen_rotate_plus_90_enter);
break;
case Surface.ROTATION_180:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_exit);
+ R.anim.screen_rotate_180_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_enter);
+ R.anim.screen_rotate_180_enter);
break;
case Surface.ROTATION_270:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_exit);
+ R.anim.screen_rotate_minus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_enter);
+ R.anim.screen_rotate_minus_90_enter);
break;
}
}
- // Initialize the animations. This is a hack, redefining what "parent"
- // means to allow supplying the last and next size. In this definition
- // "%p" is the original (let's call it "previous") size, and "%" is the
- // screen's current/new size.
- mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+ mRotateExitAnimation.restrictDuration(maxAnimationDuration);
+ mRotateExitAnimation.scaleCurrentDuration(animationScale);
+ mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+ mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
+ mRotateEnterAnimation.scaleCurrentDuration(animationScale);
+
mAnimRunning = false;
mFinishAnimReady = false;
mFinishAnimStartTime = -1;
- mRotateExitAnimation.restrictDuration(maxAnimationDuration);
- mRotateExitAnimation.scaleCurrentDuration(animationScale);
- mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
- mRotateEnterAnimation.scaleCurrentDuration(animationScale);
- mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
- mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
-
- if (!customAnim && mExitingBlackFrame == null) {
- try {
- // Compute the transformation matrix that must be applied
- // the the black frame to make it stay in the initial position
- // before the new screen rotation. This is different than the
- // snapshot transformation because the snapshot is always based
- // of the native orientation of the screen, not the orientation
- // we were last in.
- createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
-
- final Rect outer;
- final Rect inner;
- if (mForceDefaultOrientation) {
- // Going from a smaller Display to a larger Display, add curtains to sides
- // or top and bottom. Going from a larger to smaller display will result in
- // no BlackSurfaces being constructed.
- outer = mCurrentDisplayRect;
- inner = mOriginalDisplayRect;
- } else {
- outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
- inner = new Rect(0, 0, mWidth, mHeight);
- }
- mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
- SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
- mRotationLayer);
- } catch (OutOfResourcesException e) {
- Slog.w(TAG, "Unable to allocate black surface", e);
- }
+ if (customAnim) {
+ mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
+ mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
}
if (customAnim && mEnteringBlackFrame == null) {
@@ -451,7 +398,12 @@
}
}
- mSurfaceRotationAnimationController.startAnimation();
+ if (customAnim) {
+ mSurfaceRotationAnimationController.startCustomAnimation();
+ } else {
+ mSurfaceRotationAnimationController.startScreenRotationAnimation();
+ }
+
return true;
}
@@ -460,11 +412,13 @@
*/
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
if (!mStarted) {
+ mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),
+ mDisplayContent.getWindowingLayer());
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
exitAnim, enterAnim);
}
@@ -480,28 +434,28 @@
mSurfaceRotationAnimationController.cancel();
mSurfaceRotationAnimationController = null;
}
- if (mSurfaceControl != null) {
- ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mSurfaceControl);
- mSurfaceControl = null;
+
+ if (mScreenshotLayer != null) {
+ ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mScreenshotLayer);
SurfaceControl.Transaction t = mService.mTransactionFactory.get();
- if (mRotationLayer != null) {
- if (mRotationLayer.isValid()) {
- t.remove(mRotationLayer);
- }
- mRotationLayer = null;
+ if (mScreenshotLayer.isValid()) {
+ t.remove(mScreenshotLayer);
}
+ mScreenshotLayer = null;
+
if (mEnterBlackFrameLayer != null) {
if (mEnterBlackFrameLayer.isValid()) {
t.remove(mEnterBlackFrameLayer);
}
mEnterBlackFrameLayer = null;
}
+ if (mBackColorSurface != null) {
+ t.remove(mBackColorSurface);
+ mBackColorSurface = null;
+ }
t.apply();
}
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.kill();
- mExitingBlackFrame = null;
- }
+
if (mEnteringBlackFrame != null) {
mEnteringBlackFrame.kill();
mEnteringBlackFrame = null;
@@ -537,18 +491,28 @@
* Utility class that runs a {@link ScreenRotationAnimation} on the {@link
* SurfaceAnimationRunner}.
* <p>
- * The rotation animation is divided into the following hierarchy:
+ * The rotation animation supports both screen rotation and custom animations
+ *
+ * For custom animations:
* <ul>
- * <li> A first rotation layer, containing the blackframes. This layer is animated by the
- * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
- * <ul>
- * <li> A child layer containing the screenshot on which is added an animation of it's
- * alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
- * </ul>
- * <li> A second rotation layer used when custom animations are passed in
+ * <li>
+ * The screenshot layer which has an added animation of it's alpha channel
+ * ("screen_rotate_alpha") and that will be applied along with the custom animation.
+ * </li>
+ * <li> A device layer that is animated with the provided custom animation </li>
+ * </ul>
+ *
+ * For screen rotation:
+ * <ul>
+ * <li> A rotation layer that is both rotated and faded out during a single animation </li>
+ * <li> A device layer that is both rotated and faded in during a single animation </li>
+ * <li> A background color layer that transitions colors behind the first two layers </li>
+ * </ul>
+ *
* {@link ScreenRotationAnimation#startAnimation(
* SurfaceControl.Transaction, long, float, int, int, int, int)}.
* </ul>
+ *
* <p>
* Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
* this three {@link SurfaceControl}s which then delegates the animation to the
@@ -556,22 +520,35 @@
*/
class SurfaceRotationAnimationController {
private SurfaceAnimator mDisplayAnimator;
- private SurfaceAnimator mEnterBlackFrameAnimator;
private SurfaceAnimator mScreenshotRotationAnimator;
private SurfaceAnimator mRotateScreenAnimator;
+ private SurfaceAnimator mEnterBlackFrameAnimator;
+
+ void startCustomAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mRotateScreenAnimator = startScreenshotAlphaAnimation();
+ mDisplayAnimator = startDisplayRotation();
+ if (mEnteringBlackFrame != null) {
+ mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ }
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
+ }
+ }
/**
* Start the rotation animation of the display and the screenshot on the
* {@link SurfaceAnimationRunner}.
*/
- void startAnimation() {
- mRotateScreenAnimator = startScreenshotAlphaAnimation();
- mDisplayAnimator = startDisplayRotation();
- if (mExitingBlackFrame != null) {
+ void startScreenRotationAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mDisplayAnimator = startDisplayRotation();
mScreenshotRotationAnimator = startScreenshotRotationAnimation();
- }
- if (mEnteringBlackFrame != null) {
- mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ startColorAnimation();
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
}
@@ -596,8 +573,8 @@
private SurfaceAnimator startScreenshotAlphaAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mSurfaceControl)
- .setAnimationLeashParent(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
+ .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.setWidth(mWidth)
.setHeight(mHeight)
.build(),
@@ -616,13 +593,67 @@
private SurfaceAnimator startScreenshotRotationAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
.setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.build(),
createWindowAnimationSpec(mRotateExitAnimation),
this::onAnimationEnd);
}
+
+ /**
+ * Applies the color change from {@link #mStartLuma} to {@link #mEndLuma} as a
+ * grayscale color
+ */
+ private void startColorAnimation() {
+ int colorTransitionMs = mContext.getResources().getInteger(
+ R.integer.config_screen_rotation_color_transition);
+ final SurfaceAnimationRunner runner = mService.mSurfaceAnimationRunner;
+ final float[] rgbTmpFloat = new float[3];
+ final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
+ final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
+ final long duration = colorTransitionMs * (long) mService.getCurrentAnimatorScale();
+ final ArgbEvaluator va = ArgbEvaluator.getInstance();
+ runner.startAnimation(
+ new LocalAnimationAdapter.AnimationSpec() {
+ @Override
+ public long getDuration() {
+ return duration;
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+ long currentPlayTime) {
+ float fraction = (float)currentPlayTime / (float)getDuration();
+ int color = (Integer) va.evaluate(fraction, startColor, endColor);
+ Color middleColor = Color.valueOf(color);
+ rgbTmpFloat[0] = middleColor.red();
+ rgbTmpFloat[1] = middleColor.green();
+ rgbTmpFloat[2] = middleColor.blue();
+ if (leash.isValid()) {
+ t.setColor(leash, rgbTmpFloat);
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "startLuma=" + mStartLuma
+ + " endLuma=" + mEndLuma
+ + " durationMs=" + colorTransitionMs);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(ROTATE);
+ proto.write(START_LUMA, mStartLuma);
+ proto.write(END_LUMA, mEndLuma);
+ proto.write(DURATION_MS, colorTransitionMs);
+ proto.end(token);
+ }
+ },
+ mBackColorSurface, mDisplayContent.getPendingTransaction(), null);
+ }
+
private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
@@ -646,7 +677,6 @@
LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
animationSpec, mService.mSurfaceAnimationRunner);
-
animator.startAnimation(mDisplayContent.getPendingTransaction(),
localAnimationAdapter, false);
return animator;
@@ -692,7 +722,6 @@
if (mEnterBlackFrameAnimator != null) {
mEnterBlackFrameAnimator.cancelAnimation();
}
-
if (mScreenshotRotationAnimator != null) {
mScreenshotRotationAnimator.cancelAnimation();
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 50cea2e..5633b6b 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -78,6 +78,10 @@
@GuardedBy("mLock")
private boolean mAnimationStartDeferred;
+ /**
+ * There should only ever be one instance of this class. Usual spot for it is with
+ * {@link WindowManagerService}
+ */
SurfaceAnimationRunner(Supplier<Transaction> transactionFactory,
PowerManagerInternal powerManagerInternal) {
this(null /* callbackProvider */, null /* animatorFactory */,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 223e9b9..74fdba1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -205,6 +205,7 @@
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationController;
import android.view.IDockedStackListener;
@@ -2768,6 +2769,7 @@
true /* includingParents */);
}
}
+ syncInputTransactions();
}
/**
@@ -3727,6 +3729,48 @@
}
@Override
+ public void setDisplayWindowInsetsController(
+ int displayId, IDisplayWindowInsetsController insetsController) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return;
+ }
+ dc.setRemoteInsetsController(insetsController);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void modifyDisplayWindowInsets(int displayId, InsetsState state) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null || dc.mRemoteInsetsControlTarget == null) {
+ return;
+ }
+ dc.getInsetsStateController().onInsetsModified(
+ dc.mRemoteInsetsControlTarget, state);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {
@@ -7314,7 +7358,8 @@
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
- dc.mInputMethodTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(),
+ true /* fromIme */);
}
}
}
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
new file mode 100644
index 0000000..94f6676
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server.wm.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+
+/** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
+public class RotationAnimationUtils {
+
+ /**
+ * Converts the provided {@link GraphicBuffer} and converts it to a bitmap to then sample the
+ * luminance at the borders of the bitmap
+ * @return the average luminance of all the pixels at the borders of the bitmap
+ */
+ public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+ Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
+ if (hwBitmap == null) {
+ return 0;
+ }
+
+ Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
+ float totalLuma = 0;
+ int height = swaBitmap.getHeight();
+ int width = swaBitmap.getWidth();
+ int i;
+ for (i = 0; i < width; i++) {
+ totalLuma += swaBitmap.getColor(i, 0).luminance();
+ totalLuma += swaBitmap.getColor(i, height - 1).luminance();
+ }
+ for (i = 0; i < height; i++) {
+ totalLuma += swaBitmap.getColor(0, i).luminance();
+ totalLuma += swaBitmap.getColor(width - 1, i).luminance();
+ }
+ return totalLuma / (2 * width + 2 * height);
+ }
+
+ /**
+ * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
+ * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace)
+ */
+ public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
+ if (surfaceControl == null) {
+ return 0;
+ }
+
+ Point size = new Point();
+ display.getSize(size);
+ Rect crop = new Rect(0, 0, size.x, size.y);
+ SurfaceControl.ScreenshotGraphicBuffer buffer =
+ SurfaceControl.captureLayers(surfaceControl, crop, 1);
+ return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(),
+ buffer.getColorSpace());
+ }
+
+ public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ outMatrix.reset();
+ break;
+ case Surface.ROTATION_90:
+ outMatrix.setRotate(90, 0, 0);
+ outMatrix.postTranslate(height, 0);
+ break;
+ case Surface.ROTATION_180:
+ outMatrix.setRotate(180, 0, 0);
+ outMatrix.postTranslate(width, height);
+ break;
+ case Surface.ROTATION_270:
+ outMatrix.setRotate(270, 0, 0);
+ outMatrix.postTranslate(0, width);
+ break;
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 5a1d552..8641059 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -64,4 +64,8 @@
}
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {}
+
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6c2d14e..2a08f5c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8607,6 +8607,24 @@
}
@Override
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ if (!mHasFeature) {
+ return false;
+ }
+ enforceManageUsers();
+
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ for (UserInfo ui : mUserManager.getUsers()) {
+ if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ }
+
+ @Override
public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
ensureCallerIdentityMatchesIfNotSystem(packageName, pid, uid);
diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
new file mode 100644
index 0000000..4cbdbd17
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Unit tests for {@link LocationRequestStatistics}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class LocationRequestStatisticsTest {
+
+ /**
+ * Check adding and removing requests & strings
+ */
+ @Test
+ public void testRequestSummary() {
+ LocationRequestStatistics.RequestSummary summary =
+ new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps", 1000);
+ StringWriter stringWriter = new StringWriter();
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234);
+ assertThat(stringWriter.toString()).startsWith("At");
+
+ StringWriter stringWriterRemove = new StringWriter();
+ summary = new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps",
+ LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345);
+ assertThat(stringWriterRemove.toString()).contains("-");
+ }
+
+ /**
+ * Check summary list size capping
+ */
+ @Test
+ public void testSummaryList() {
+ LocationRequestStatistics statistics = new LocationRequestStatistics();
+ statistics.history.addRequest("com.example", "gps", 1000);
+ assertThat(statistics.history.mList.size()).isEqualTo(1);
+ // Try (not) to overflow
+ for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
+ statistics.history.addRequest("com.example", "gps", 1000);
+ }
+ assertThat(statistics.history.mList.size()).isEqualTo(
+ LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
new file mode 100644
index 0000000..d0767cc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server.compat;
+
+import android.content.pm.ApplicationInfo;
+
+class ApplicationInfoBuilder {
+ private boolean mIsDebuggable;
+ private int mTargetSdk;
+ private String mPackageName;
+
+ private ApplicationInfoBuilder() {
+ mTargetSdk = -1;
+ }
+
+ static ApplicationInfoBuilder create() {
+ return new ApplicationInfoBuilder();
+ }
+
+ ApplicationInfoBuilder withTargetSdk(int targetSdk) {
+ mTargetSdk = targetSdk;
+ return this;
+ }
+
+ ApplicationInfoBuilder debuggable() {
+ mIsDebuggable = true;
+ return this;
+ }
+
+ ApplicationInfoBuilder withPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ ApplicationInfo build() {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ if (mIsDebuggable) {
+ applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+ }
+ applicationInfo.packageName = mPackageName;
+ applicationInfo.targetSdkVersion = mTargetSdk;
+ return applicationInfo;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
new file mode 100644
index 0000000..328c71d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -0,0 +1,99 @@
+/*
+ * 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.server.compat;
+
+import android.content.Context;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class for creating a CompatConfig.
+ */
+class CompatConfigBuilder {
+ private ArrayList<CompatChange> mChanges;
+ private AndroidBuildClassifier mBuildClassifier;
+ private Context mContext;
+
+ private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) {
+ mChanges = new ArrayList<>();
+ mBuildClassifier = buildClassifier;
+ mContext = context;
+ }
+
+ static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) {
+ return new CompatConfigBuilder(buildClassifier, context);
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
+ mChanges.add(new CompatChange(id, name, sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
+ String description) {
+ mChanges.add(new CompatChange(id, "", sdk, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, false, ""));
+ return this;
+ }
+ CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, true, description));
+ return this;
+ }
+
+ CompatConfig build() {
+ CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
+ for (CompatChange change : mChanges) {
+ config.addChange(change);
+ }
+ return config;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index cb99c11..407f67e 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,12 +18,25 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.File;
import java.io.FileOutputStream;
@@ -34,12 +47,12 @@
@RunWith(AndroidJUnit4.class)
public class CompatConfigTest {
- private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
- ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = pName;
- ai.targetSdkVersion = targetSdkVersion;
- return ai;
- }
+ @Mock
+ private Context mContext;
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
private File createTempDir() {
String base = System.getProperty("java.io.tmpdir");
@@ -54,112 +67,206 @@
os.close();
}
- @Test
- public void testUnknownChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
}
@Test
- public void testDisabledChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ public void testUnknownChangeEnabled() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isTrue();
}
@Test
- public void testTargetSdkChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ public void testDisabledChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isFalse();
}
@Test
- public void testTargetSdkChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ public void testTargetSdkChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(2).build()))
+ .isFalse();
}
@Test
- public void testDisabledOverrideTargetSdkChange() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
+ public void testTargetSdkChangeEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
}
@Test
- public void testGetDisabledChanges() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null));
- pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
+ public void testDisabledOverrideTargetSdkChange() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkDisabledChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse();
}
@Test
- public void testGetDisabledChangesSorted() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
+ public void testGetDisabledChanges() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addEnabledChangeWithId(2345L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(
+ ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L);
}
@Test
- public void testPackageOverrideEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled
- pc.addOverride(1234L, "com.some.package", true);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
+ public void testGetDisabledChangesSorted() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addDisabledChangeWithId(123L)
+ .addDisabledChangeWithId(12L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build()))
+ .asList().containsExactly(12L, 123L, 1234L);
}
@Test
- public void testPackageOverrideDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPackageOverrideEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isFalse();
}
@Test
- public void testPackageOverrideUnknownPackage() {
- CompatConfig pc = new CompatConfig();
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPackageOverrideDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testPackageOverrideUnknownChange() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ public void testPackageOverrideUnknownPackage() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testRemovePackageOverride() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- pc.removeOverride(1234L, "com.some.package");
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ public void testPreventAddOverride() throws Exception {
+ final long changeId = 1234L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ assertThrows(SecurityException.class,
+ () -> compatConfig.addOverride(1234L, "com.some.package", true)
+ );
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
}
@Test
- public void testLookupChangeId() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null));
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ public void testPreventRemoveOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+ // Assume the override was allowed to be added.
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ // Validator allows turning on the change.
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+
+ // Reject all override attempts.
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+ // Try to turn off change, but validator prevents it.
+ assertThrows(SecurityException.class,
+ () -> compatConfig.removeOverride(1234L, "com.some.package"));
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
- public void testLookupChangeIdNotPresent() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
+ public void testRemovePackageOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+
+ assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+ compatConfig.removeOverride(1234L, "com.some.package");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+ }
+
+ @Test
+ public void testLookupChangeId() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
+ .addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE")
+ .build();
+
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ }
+
+ @Test
+ public void testLookupChangeIdNotPresent() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
}
@Test
@@ -172,14 +279,17 @@
File dir = createTempDir();
writeToFile(dir, "platform_compat_config.xml", configXml);
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
@Test
@@ -195,15 +305,16 @@
File dir = createTempDir();
writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
}
-
-
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
new file mode 100644
index 0000000..793296e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * 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.server.compat;
+
+import android.compat.Compatibility;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class CompatibilityChangeConfigBuilder {
+ private Set<Long> mEnabled;
+ private Set<Long> mDisabled;
+
+ private CompatibilityChangeConfigBuilder() {
+ mEnabled = new HashSet<>();
+ mDisabled = new HashSet<>();
+ }
+
+ static CompatibilityChangeConfigBuilder create() {
+ return new CompatibilityChangeConfigBuilder();
+ }
+
+ CompatibilityChangeConfigBuilder enable(Long id) {
+ mEnabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfigBuilder disable(Long id) {
+ mDisabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfig build() {
+ return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
new file mode 100644
index 0000000..ecd07bd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -0,0 +1,383 @@
+/*
+ * 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.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class OverrideValidatorImplTest {
+ private static final String PACKAGE_NAME = "my.package";
+ private static final int TARGET_SDK = 10;
+ private static final int TARGET_SDK_BEFORE = 9;
+ private static final int TARGET_SDK_AFTER = 11;
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ Context mContext;
+
+ private AndroidBuildClassifier debuggableBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier betaBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(false);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier finalBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
+ TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index c406876..ce5d6d9 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -26,21 +26,20 @@
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.testng.Assert.assertThrows;
-import android.compat.Compatibility;
import android.content.Context;
import android.content.pm.PackageManager;
-import com.android.internal.compat.CompatibilityChangeConfig;
+import androidx.test.runner.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
+import com.android.internal.compat.AndroidBuildClassifier;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.MockitoAnnotations;
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PlatformCompatTest {
private static final String PACKAGE_NAME = "my.package";
@@ -50,84 +49,77 @@
private PackageManager mPackageManager;
@Mock
CompatChange.ChangeListener mListener1, mListener2;
-
+ PlatformCompat mPlatformCompat;
+ CompatConfig mCompatConfig;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
new PackageManager.NameNotFoundException());
- CompatConfig.get().clearChanges();
+ mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
}
@Test
- public void testRegisterListenerToSameIdThrows() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
+ public void testRegisterListenerToSameIdThrows() throws Exception {
// Registering a listener to change 1 is successful.
- pc.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(1, mListener1);
// Registering a listener to change 2 is successful.
- pc.registerListener(2, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
// Trying to register another listener to change id 1 fails.
- assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
+ assertThrows(IllegalStateException.class,
+ () -> mPlatformCompat.registerListener(1, mListener1));
}
@Test
- public void testRegisterListenerReturn() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ public void testRegisterListenerReturn() throws Exception {
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
// Change id 1 is known (added in setOverrides).
- assertThat(pc.registerListener(1, mListener1)).isTrue();
+ assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue();
// Change 2 is unknown.
- assertThat(pc.registerListener(2, mListener1)).isFalse();
+ assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse();
}
@Test
- public void testListenerCalledOnSetOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnSetOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerNotCalledOnWrongPackage() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerNotCalledOnWrongPackage() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
-
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, never()).onCompatChange("other.package");
}
@Test
- public void testListenerCalledOnSetOverridesTwoListeners() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -136,11 +128,10 @@
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -148,31 +139,23 @@
}
@Test
- public void testListenerCalledOnSetOverridesForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnSetOverridesForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
-
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnSetOverridesTwoListenersForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -181,10 +164,10 @@
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.registerListener(2, mListener2);
+
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -192,15 +175,12 @@
}
@Test
- public void testListenerCalledOnClearOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -208,21 +188,18 @@
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverridesMultipleOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
@@ -230,21 +207,18 @@
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideExists() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrideExists() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -252,21 +226,17 @@
reset(mListener1);
reset(mListener2);
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideDoesntExist() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- pc.registerListener(1, mListener1);
-
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
// Listener not called when a non existing override is removed.
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
}
-
-
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a16e14f..175c756 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3636,6 +3636,29 @@
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
+ public void testIsOrganizationOwnedDevice() throws Exception {
+ setupProfileOwner();
+ // Set up the user manager to return correct user info
+ UserInfo managedProfileUserInfo = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
+ "managed profile",
+ UserInfo.FLAG_MANAGED_PROFILE);
+ when(getServices().userManager.getUsers())
+ .thenReturn(Arrays.asList(managedProfileUserInfo));
+
+ // Any caller without the MANAGE_USERS permission should get a security exception.
+ assertExpectException(SecurityException.class, null, () ->
+ dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ // But when the right permission is granted, this should succeed.
+ mContext.permissions.add(android.Manifest.permission.MANAGE_USERS);
+ assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+
+ // A random caller from another user should also be able to get the right result.
+ mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
new file mode 100644
index 0000000..742952e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 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.server.integrity.parser;
+
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class RuleIndexingControllerTest {
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ddd")
+ .setAppCertificate("777")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysInFirstAndLastBlock() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("bbb")
+ .setAppCertificate("999")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 200),
+ new RuleIndexRange(800, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysMatchWithValues() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_noIndexesAvailable() throws IOException {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 500),
+ new RuleIndexRange(500, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ private static InputStream obtainDefaultIndexingMapForTest() {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString("ccc", 200)
+ + getKeyValueString("eee", 300)
+ + getKeyValueString("hhh", 400)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString("111", 600)
+ + getKeyValueString("444", 700)
+ + getKeyValueString("888", 800)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ return new ByteArrayInputStream(rule.array());
+ }
+
+ private static String getKeyValueString(String key, int value) {
+ String isNotHashed = "0";
+ return isNotHashed
+ + getBits(key.length(), VALUE_SIZE_BITS)
+ + getValueBits(key)
+ + getBits(value, /* numOfBits= */ 32);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 71b568c..ae53692 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -37,7 +37,7 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index ca6fd08..aaf9799 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -30,7 +30,7 @@
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
index 239d413..f1e9191 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 73dd2df..f2ba97c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,8 @@
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -86,6 +88,7 @@
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewRootImpl;
+import android.view.WindowManager;
import android.view.test.InsetsModeSession;
import androidx.test.filters.SmallTest;
@@ -561,8 +564,7 @@
final DisplayContent dc = createNewDisplay();
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
}
@@ -829,8 +831,7 @@
win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
dc.updateSystemGestureExclusion();
@@ -866,8 +867,7 @@
win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -898,8 +898,7 @@
win2.getAttrs().height = 10;
win2.setSystemGestureExclusion(Collections.emptyList());
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -922,8 +921,7 @@
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
win.mActivityRecord.mTargetSdk = P;
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
@@ -935,6 +933,22 @@
}
@Test
+ public void testRequestResizeForEmptyFrames() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.setRequestedSize(mDisplayContent.mBaseDisplayWidth, 0 /* height */);
+ win.mAttrs.width = win.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ win.mAttrs.gravity = Gravity.CENTER;
+ performLayout(mDisplayContent);
+
+ // The frame is empty because the requested height is zero.
+ assertTrue(win.getFrameLw().isEmpty());
+ // The window should be scheduled to resize then the client may report a new non-empty size.
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).contains(win);
+ }
+
+ @Test
public void testOrientationChangeLogging() {
MetricsLogger mockLogger = mock(MetricsLogger.class);
Configuration oldConfig = new Configuration();
@@ -1011,6 +1025,11 @@
mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
}
+ private void performLayout(DisplayContent dc) {
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ }
+
/**
* Create DisplayContent that does not update display base/initial values from device to keep
* the values set by test.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ea88315..31a7f24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,6 +44,7 @@
import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl.Transaction;
+import android.view.View;
import android.view.WindowManager;
import com.android.server.AttributeCache;
@@ -312,6 +313,16 @@
}
}
+ static void makeWindowVisible(WindowState... windows) {
+ for (WindowState win : windows) {
+ win.mViewVisibility = View.VISIBLE;
+ win.mRelayoutCalled = true;
+ win.mHasSurface = true;
+ win.mHidden = false;
+ win.showLw(false /* doAnimation */, false /* requestAnim */);
+ }
+ }
+
/** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */
ActivityStack createTaskStackOnDisplay(DisplayContent dc) {
return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
new file mode 100644
index 0000000..9cda084
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.server.wm.utils;
+
+import static android.graphics.Bitmap.Config.ARGB_8888;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.view.Surface;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RotationAnimationUtilsTest {
+
+ private static final int BITMAP_HEIGHT = 100;
+ private static final int BITMAP_WIDTH = 100;
+ private static final int POINT_WIDTH = 1000;
+ private static final int POINT_HEIGHT = 2000;
+
+ private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+ private Matrix mMatrix;
+
+ @Before
+ public void setup() {
+ mMatrix = new Matrix();
+ }
+
+ @Test
+ public void blackLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteImageBlackBorderLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ setBorderLuma(swBitmap, 0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void blackImageWhiteBorderLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ setBorderLuma(swBitmap, 1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void rotate_0_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_0,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_WIDTH, newPoints.x, 0);
+ assertEquals(POINT_HEIGHT, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_90_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_90,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(POINT_WIDTH, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_180_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_180,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_270_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_270,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_HEIGHT, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ private PointF checkMappedPoints(int x, int y) {
+ final float[] fs = new float[] {x, y};
+ mMatrix.mapPoints(fs);
+ return new PointF(fs[0], fs[1]);
+ }
+
+ private Bitmap createBitmap(float luma) {
+ Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888);
+ for (int i = 0; i < BITMAP_WIDTH; i++) {
+ for (int j = 0; j < BITMAP_HEIGHT; j++) {
+ bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma));
+ }
+ }
+ return bitmap;
+ }
+
+ private GraphicBuffer swBitmapToGraphicsBuffer(Bitmap swBitmap) {
+ Bitmap hwBitmap = swBitmap.copy(Bitmap.Config.HARDWARE, false);
+ return hwBitmap.createGraphicBufferHandle();
+ }
+
+ private void setBorderLuma(Bitmap swBitmap, float luma) {
+ int i;
+ int width = swBitmap.getWidth();
+ int height = swBitmap.getHeight();
+ for (i = 0; i < width; i++) {
+ swBitmap.setPixel(i, 0, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(i, height - 1, Color.argb(1, luma, luma, luma));
+ }
+ for (i = 0; i < height; i++) {
+ swBitmap.setPixel(0, i, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(width - 1, i, Color.argb(1, luma, luma, luma));
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index b75510b..488ee78 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -83,7 +83,7 @@
* could transition to INTENT_STARTED.
*
* <p> If any bad transition happened, the state becomse UNKNOWN. The UNKNOWN state
- * could be * accumulated, because during the UNKNOWN state more IntentStarted may
+ * could be accumulated, because during the UNKNOWN state more IntentStarted may
* be triggered. To recover from UNKNOWN to INIT, all the accumualted IntentStarted
* should termniate.
*
@@ -100,7 +100,7 @@
@Override
public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentStarted during UNKNOWN." + intent);
+ Log.wtf(TAG, "IntentStarted during UNKNOWN." + intent);
incAccIntentStartedEvents();
return;
}
@@ -110,32 +110,32 @@
state != State.ACTIVITY_CANCELLED &&
state != State.ACTIVITY_FINISHED &&
state != State.REPORT_FULLY_DRAWN) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
incAccIntentStartedEvents();
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_STARTED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED));
state = State.INTENT_STARTED;
}
@Override
public void onIntentFailed() {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentFailed during UNKNOWN.");
+ Log.wtf(TAG, "IntentFailed during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_FAILED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED));
state = State.INTENT_FAILED;
}
@@ -143,11 +143,11 @@
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
@Temperature int temperature) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunched during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunched during UNKNOWN.");
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
incAccIntentStartedEvents();
return;
@@ -160,12 +160,12 @@
@Override
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchCancelled during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchCancelled during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
incAccIntentStartedEvents();
return;
@@ -179,13 +179,13 @@
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchFinished during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchFinished during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
incAccIntentStartedEvents();
return;
@@ -199,7 +199,7 @@
public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onReportFullyDrawn during UNKNOWN.");
+ Log.wtf(TAG, "onReportFullyDrawn during UNKNOWN.");
return;
}
if (state == State.INIT) {
@@ -207,7 +207,7 @@
}
if (state != State.ACTIVITY_FINISHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
return;
}
@@ -230,7 +230,7 @@
private void incAccIntentStartedEvents() {
if (accIntentStartedEvents < 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if (accIntentStartedEvents == 0) {
state = State.UNKNOWN;
@@ -243,7 +243,7 @@
private void decAccIntentStartedEvents() {
if (accIntentStartedEvents <= 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if(accIntentStartedEvents == 1) {
state = State.INIT;
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
rename to telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fdf8849..5baddef 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
@@ -4205,8 +4204,11 @@
/** @hide */
@Nullable
private ICarrierConfigLoader getICarrierConfigLoader() {
- return ICarrierConfigLoader.Stub
- .asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
+ return ICarrierConfigLoader.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getCarrierConfigServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index ce32dce..5345469 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -191,6 +191,7 @@
*
* @hide
*/
+ @SystemApi
public abstract @NonNull CellIdentity sanitizeLocationInfo();
@Override
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 64776e3..1193199 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -19,7 +19,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
@@ -38,7 +37,11 @@
*/
public static void requestLocationUpdate() {
try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
+ ITelephony phone = ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (phone != null) {
phone.updateServiceLocation();
}
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 202da68..b10649c 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -17,9 +17,7 @@
package android.telephony;
import android.annotation.IntDef;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import com.android.internal.telephony.ITelephony;
@@ -148,6 +146,9 @@
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index fbe355e..eb328a7 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -35,7 +35,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -745,7 +744,11 @@
"Invalid pdu format. format must be either 3gpp or 3gpp2");
}
try {
- ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ ISms iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
if (iSms != null) {
iSms.injectSmsPduForSubscriber(
getSubscriptionId(), pdu, format, receivedIntent);
@@ -1535,7 +1538,10 @@
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
@@ -1573,7 +1579,11 @@
}
private static ISms getISmsService() {
- return ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ return ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
}
/**
@@ -2007,7 +2017,11 @@
public boolean isSMSPromptEnabled() {
ISms iSms = null;
try {
- iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
return iSms.isSMSPromptEnabled();
} catch (RemoteException ex) {
return false;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 22eed6e..88501a7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,6 @@
import android.os.ParcelUuid;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.provider.Telephony.SimInfo;
import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsMmTelManager;
@@ -265,7 +264,7 @@
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID;
/**
* TelephonyProvider column name for a unique identifier for the subscription within the
@@ -274,18 +273,18 @@
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String ICC_ID = "icc_id";
+ public static final String ICC_ID = SimInfo.ICC_ID;
/**
* TelephonyProvider column name for user SIM_SlOT_INDEX
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String SIM_SLOT_INDEX = "sim_id";
+ public static final String SIM_SLOT_INDEX = SimInfo.SIM_SLOT_INDEX;
/** SIM is not inserted */
/** @hide */
- public static final int SIM_NOT_INSERTED = -1;
+ public static final int SIM_NOT_INSERTED = SimInfo.SIM_NOT_INSERTED;
/**
* The slot-index for Bluetooth Remote-SIM subscriptions
@@ -300,23 +299,7 @@
* Default value is 0.
*/
/** @hide */
- public static final String SUBSCRIPTION_TYPE = "subscription_type";
-
- /**
- * TelephonyProvider column name white_listed_apn_data.
- * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
- * and mobile data is turned off by the user.
- * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
- * data connection to setup even if MMS is metered and mobile_data is turned off on that
- * subscription.
- *
- * Default value is 0.
- *
- * @deprecated Replaced by {@link #DATA_ENABLED_OVERRIDE_RULES}
- * @hide
- */
- @Deprecated
- public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+ public static final String SUBSCRIPTION_TYPE = SimInfo.SUBSCRIPTION_TYPE;
/**
* TelephonyProvider column name data_enabled_override_rules.
@@ -329,7 +312,15 @@
*
* @hide
*/
- public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ public static final String DATA_ENABLED_OVERRIDE_RULES = SimInfo.DATA_ENABLED_OVERRIDE_RULES;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+ value = {
+ SUBSCRIPTION_TYPE_LOCAL_SIM,
+ SUBSCRIPTION_TYPE_REMOTE_SIM})
+ public @interface SubscriptionType {}
/**
* This constant is to designate a subscription as a Local-SIM Subscription.
@@ -337,7 +328,7 @@
* device.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM;
/**
* This constant is to designate a subscription as a Remote-SIM Subscription.
@@ -363,29 +354,21 @@
* was never seen before.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
- value = {
- SUBSCRIPTION_TYPE_LOCAL_SIM,
- SUBSCRIPTION_TYPE_REMOTE_SIM})
- public @interface SubscriptionType {}
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = SimInfo.SUBSCRIPTION_TYPE_REMOTE_SIM;
/**
* TelephonyProvider column name for user displayed name.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME = SimInfo.DISPLAY_NAME;
/**
* TelephonyProvider column name for the service provider name for the SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String CARRIER_NAME = "carrier_name";
+ public static final String CARRIER_NAME = SimInfo.CARRIER_NAME;
/**
* Default name resource
@@ -399,44 +382,44 @@
*
* @hide
*/
- public static final String NAME_SOURCE = "name_source";
+ public static final String NAME_SOURCE = SimInfo.NAME_SOURCE;
/**
* The name_source is the default, which is from the carrier id.
* @hide
*/
- public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+ public static final int NAME_SOURCE_DEFAULT = SimInfo.NAME_SOURCE_DEFAULT;
/**
* The name_source is from SIM EF_SPN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_SPN = 1;
+ public static final int NAME_SOURCE_SIM_SPN = SimInfo.NAME_SOURCE_SIM_SPN;
/**
* The name_source is from user input
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final int NAME_SOURCE_USER_INPUT = 2;
+ public static final int NAME_SOURCE_USER_INPUT = SimInfo.NAME_SOURCE_USER_INPUT;
/**
* The name_source is carrier (carrier app, carrier config, etc.)
* @hide
*/
- public static final int NAME_SOURCE_CARRIER = 3;
+ public static final int NAME_SOURCE_CARRIER = SimInfo.NAME_SOURCE_CARRIER;
/**
* The name_source is from SIM EF_PNN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_PNN = 4;
+ public static final int NAME_SOURCE_SIM_PNN = SimInfo.NAME_SOURCE_SIM_PNN;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"NAME_SOURCE_"},
value = {
- NAME_SOURCE_DEFAULT_SOURCE,
+ NAME_SOURCE_DEFAULT,
NAME_SOURCE_SIM_SPN,
NAME_SOURCE_USER_INPUT,
NAME_SOURCE_CARRIER,
@@ -449,67 +432,30 @@
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String COLOR = "color";
-
- /** @hide */
- public static final int COLOR_1 = 0;
-
- /** @hide */
- public static final int COLOR_2 = 1;
-
- /** @hide */
- public static final int COLOR_3 = 2;
-
- /** @hide */
- public static final int COLOR_4 = 3;
-
- /** @hide */
- public static final int COLOR_DEFAULT = COLOR_1;
+ public static final String COLOR = SimInfo.COLOR;
/**
* TelephonyProvider column name for the phone number of a SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String NUMBER = "number";
+ public static final String NUMBER = SimInfo.NUMBER;
/**
- * TelephonyProvider column name for the number display format of a SIM.
+ * TelephonyProvider column name for whether data roaming is enabled.
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
-
- /** @hide */
- public static final int DISPLAY_NUMBER_NONE = 0;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_FIRST = 1;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_LAST = 2;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
-
- /**
- * TelephonyProvider column name for permission for data roaming of a SIM.
- * <P>Type: INTEGER (int)</P>
- */
- /** @hide */
- public static final String DATA_ROAMING = "data_roaming";
+ public static final String DATA_ROAMING = SimInfo.DATA_ROAMING;
/** Indicates that data roaming is enabled for a subscription */
- public static final int DATA_ROAMING_ENABLE = 1;
+ public static final int DATA_ROAMING_ENABLE = SimInfo.DATA_ROAMING_ENABLE;
/** Indicates that data roaming is disabled for a subscription */
- public static final int DATA_ROAMING_DISABLE = 0;
+ public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
/** @hide */
- public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
-
- /** @hide */
- public static final int SIM_PROVISIONED = 0;
+ public static final int DATA_ROAMING_DEFAULT = SimInfo.DATA_ROAMING_DEFAULT;
/**
* TelephonyProvider column name for subscription carrier id.
@@ -517,61 +463,61 @@
* <p>Type: INTEGER (int) </p>
* @hide
*/
- public static final String CARRIER_ID = "carrier_id";
+ public static final String CARRIER_ID = SimInfo.CARRIER_ID;
/**
* @hide A comma-separated list of EHPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String EHPLMNS = "ehplmns";
+ public static final String EHPLMNS = SimInfo.EHPLMNS;
/**
* @hide A comma-separated list of HPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String HPLMNS = "hplmns";
+ public static final String HPLMNS = SimInfo.HPLMNS;
/**
* TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MCC_STRING = "mcc_string";
+ public static final String MCC_STRING = SimInfo.MCC_STRING;
/**
* TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MNC_STRING = "mnc_string";
+ public static final String MNC_STRING = SimInfo.MNC_STRING;
/**
* TelephonyProvider column name for the MCC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MCC = "mcc";
+ public static final String MCC = SimInfo.MCC;
/**
* TelephonyProvider column name for the MNC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MNC = "mnc";
+ public static final String MNC = SimInfo.MNC;
/**
* TelephonyProvider column name for the iso country code associated with a SIM.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ public static final String ISO_COUNTRY_CODE = SimInfo.ISO_COUNTRY_CODE;
/**
* TelephonyProvider column name for the sim provisioning status associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+ public static final String SIM_PROVISIONING_STATUS = SimInfo.SIM_PROVISIONING_STATUS;
/**
* TelephonyProvider column name for whether a subscription is embedded (that is, present on an
@@ -579,7 +525,7 @@
* <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
* @hide
*/
- public static final String IS_EMBEDDED = "is_embedded";
+ public static final String IS_EMBEDDED = SimInfo.IS_EMBEDDED;
/**
* TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
@@ -587,7 +533,7 @@
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String CARD_ID = "card_id";
+ public static final String CARD_ID = SimInfo.CARD_ID;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -595,7 +541,7 @@
* <p>TYPE: BLOB
* @hide
*/
- public static final String ACCESS_RULES = "access_rules";
+ public static final String ACCESS_RULES = SimInfo.ACCESS_RULES;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -605,7 +551,7 @@
* @hide
*/
public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
- "access_rules_from_carrier_configs";
+ SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS;
/**
* TelephonyProvider column name identifying whether an embedded subscription is on a removable
@@ -615,79 +561,79 @@
* <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
* @hide
*/
- public static final String IS_REMOVABLE = "is_removable";
+ public static final String IS_REMOVABLE = SimInfo.IS_REMOVABLE;
/**
* TelephonyProvider column name for extreme threat in CB settings
* @hide
*/
- public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ public static final String CB_EXTREME_THREAT_ALERT = SimInfo.CB_EXTREME_THREAT_ALERT;
/**
* TelephonyProvider column name for severe threat in CB settings
*@hide
*/
- public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ public static final String CB_SEVERE_THREAT_ALERT = SimInfo.CB_SEVERE_THREAT_ALERT;
/**
* TelephonyProvider column name for amber alert in CB settings
*@hide
*/
- public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ public static final String CB_AMBER_ALERT = SimInfo.CB_AMBER_ALERT;
/**
* TelephonyProvider column name for emergency alert in CB settings
*@hide
*/
- public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ public static final String CB_EMERGENCY_ALERT = SimInfo.CB_EMERGENCY_ALERT;
/**
* TelephonyProvider column name for alert sound duration in CB settings
*@hide
*/
- public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ public static final String CB_ALERT_SOUND_DURATION = SimInfo.CB_ALERT_SOUND_DURATION;
/**
* TelephonyProvider column name for alert reminder interval in CB settings
*@hide
*/
- public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ public static final String CB_ALERT_REMINDER_INTERVAL = SimInfo.CB_ALERT_REMINDER_INTERVAL;
/**
* TelephonyProvider column name for enabling vibrate in CB settings
*@hide
*/
- public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ public static final String CB_ALERT_VIBRATE = SimInfo.CB_ALERT_VIBRATE;
/**
* TelephonyProvider column name for enabling alert speech in CB settings
*@hide
*/
- public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ public static final String CB_ALERT_SPEECH = SimInfo.CB_ALERT_SPEECH;
/**
* TelephonyProvider column name for ETWS test alert in CB settings
*@hide
*/
- public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ public static final String CB_ETWS_TEST_ALERT = SimInfo.CB_ETWS_TEST_ALERT;
/**
* TelephonyProvider column name for enable channel50 alert in CB settings
*@hide
*/
- public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ public static final String CB_CHANNEL_50_ALERT = SimInfo.CB_CHANNEL_50_ALERT;
/**
* TelephonyProvider column name for CMAS test alert in CB settings
*@hide
*/
- public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+ public static final String CB_CMAS_TEST_ALERT = SimInfo.CB_CMAS_TEST_ALERT;
/**
* TelephonyProvider column name for Opt out dialog in CB settings
*@hide
*/
- public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ public static final String CB_OPT_OUT_DIALOG = SimInfo.CB_OPT_OUT_DIALOG;
/**
* TelephonyProvider column name for enable Volte.
@@ -696,37 +642,37 @@
* {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
*@hide
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ public static final String ENHANCED_4G_MODE_ENABLED = SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* TelephonyProvider column name for enable VT (Video Telephony over IMS)
*@hide
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ public static final String VT_IMS_ENABLED = SimInfo.VT_IMS_ENABLED;
/**
* TelephonyProvider column name for enable Wifi calling
*@hide
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ public static final String WFC_IMS_ENABLED = SimInfo.WFC_IMS_ENABLED;
/**
* TelephonyProvider column name for Wifi calling mode
*@hide
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ public static final String WFC_IMS_MODE = SimInfo.WFC_IMS_MODE;
/**
* TelephonyProvider column name for Wifi calling mode in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ public static final String WFC_IMS_ROAMING_MODE = SimInfo.WFC_IMS_ROAMING_MODE;
/**
* TelephonyProvider column name for enable Wifi calling in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* TelephonyProvider column name for whether a subscription is opportunistic, that is,
@@ -735,7 +681,7 @@
* <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
* @hide
*/
- public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ public static final String IS_OPPORTUNISTIC = SimInfo.IS_OPPORTUNISTIC;
/**
* TelephonyProvider column name for group ID. Subscriptions with same group ID
@@ -744,7 +690,7 @@
*
* @hide
*/
- public static final String GROUP_UUID = "group_uuid";
+ public static final String GROUP_UUID = SimInfo.GROUP_UUID;
/**
* TelephonyProvider column name for group owner. It's the package name who created
@@ -752,14 +698,7 @@
*
* @hide
*/
- public static final String GROUP_OWNER = "group_owner";
-
- /**
- * TelephonyProvider column name for whether a subscription is metered or not, that is, whether
- * the network it connects to charges for subscription or not. For example, paid CBRS or unpaid.
- * @hide
- */
- public static final String IS_METERED = "is_metered";
+ public static final String GROUP_OWNER = SimInfo.GROUP_OWNER;
/**
* TelephonyProvider column name for the profile class of a subscription
@@ -767,7 +706,7 @@
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String PROFILE_CLASS = "profile_class";
+ public static final String PROFILE_CLASS = SimInfo.PROFILE_CLASS;
/**
* Profile class of the subscription
@@ -775,11 +714,11 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "PROFILE_CLASS_" }, value = {
- PROFILE_CLASS_TESTING,
- PROFILE_CLASS_PROVISIONING,
- PROFILE_CLASS_OPERATIONAL,
- PROFILE_CLASS_UNSET,
- PROFILE_CLASS_DEFAULT
+ SimInfo.PROFILE_CLASS_TESTING,
+ SimInfo.PROFILE_CLASS_PROVISIONING,
+ SimInfo.PROFILE_CLASS_OPERATIONAL,
+ SimInfo.PROFILE_CLASS_UNSET,
+ SimInfo.PROFILE_CLASS_DEFAULT
})
public @interface ProfileClass {}
@@ -791,7 +730,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_TESTING = 0;
+ public static final int PROFILE_CLASS_TESTING = SimInfo.PROFILE_CLASS_TESTING;
/**
* A provisioning profile is pre-loaded onto the eUICC and
@@ -800,7 +739,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_PROVISIONING = 1;
+ public static final int PROFILE_CLASS_PROVISIONING = SimInfo.PROFILE_CLASS_PROVISIONING;
/**
* An operational profile can be pre-loaded or downloaded
@@ -809,7 +748,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_OPERATIONAL = 2;
+ public static final int PROFILE_CLASS_OPERATIONAL = SimInfo.PROFILE_CLASS_OPERATIONAL;
/**
* The profile class is unset. This occurs when profile class
@@ -818,14 +757,14 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_UNSET = -1;
+ public static final int PROFILE_CLASS_UNSET = SimInfo.PROFILE_CLASS_UNSET;
/**
* Default profile class
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+ public static final int PROFILE_CLASS_DEFAULT = SimInfo.PROFILE_CLASS_DEFAULT;
/**
* IMSI (International Mobile Subscriber Identity).
@@ -833,13 +772,13 @@
* @hide
*/
//TODO: add @SystemApi
- public static final String IMSI = "imsi";
+ public static final String IMSI = SimInfo.IMSI;
/**
* Whether uicc applications is set to be enabled or disabled. By default it's enabled.
* @hide
*/
- public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ public static final String UICC_APPLICATIONS_ENABLED = SimInfo.UICC_APPLICATIONS_ENABLED;
/**
* Broadcast Action: The user has changed one of the default subs related to
@@ -1023,8 +962,11 @@
private final INetworkPolicyManager getNetworkPolicy() {
if (mNetworkPolicy == null) {
- mNetworkPolicy = INetworkPolicyManager.Stub
- .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ mNetworkPolicy = INetworkPolicyManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getNetworkPolicyServiceRegisterer()
+ .get());
}
return mNetworkPolicy;
}
@@ -1185,7 +1127,11 @@
SubscriptionInfo subInfo = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1219,7 +1165,11 @@
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1253,7 +1203,11 @@
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
mContext.getOpPackageName(), mContext.getFeatureId());
@@ -1277,7 +1231,11 @@
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1358,7 +1316,11 @@
List<SubscriptionInfo> activeList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1409,7 +1371,11 @@
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1448,7 +1414,11 @@
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
}
@@ -1477,7 +1447,11 @@
public void requestEmbeddedSubscriptionInfoListRefresh() {
int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1506,7 +1480,11 @@
@SystemApi
public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1527,7 +1505,11 @@
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1556,7 +1538,11 @@
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1577,7 +1563,11 @@
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCountMax();
}
@@ -1634,7 +1624,11 @@
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1668,7 +1662,11 @@
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1771,7 +1769,11 @@
int result = INVALID_SIM_SLOT_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSlotIndex(subscriptionId);
}
@@ -1805,7 +1807,11 @@
int[] subId = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getSubId(slotIndex);
}
@@ -1829,7 +1835,11 @@
int result = INVALID_PHONE_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getPhoneId(subId);
}
@@ -1863,7 +1873,11 @@
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSubId();
}
@@ -1886,7 +1900,11 @@
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultVoiceSubId();
}
@@ -1916,7 +1934,11 @@
public void setDefaultVoiceSubscriptionId(int subscriptionId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultVoiceSubId(subscriptionId);
}
@@ -1964,7 +1986,11 @@
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSmsSubId();
}
@@ -1990,7 +2016,11 @@
public void setDefaultSmsSubId(int subscriptionId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultSmsSubId(subscriptionId);
}
@@ -2028,7 +2058,11 @@
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultDataSubId();
}
@@ -2054,7 +2088,11 @@
public void setDefaultDataSubId(int subscriptionId) {
if (VDBG) logd("setDataSubscription sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultDataSubId(subscriptionId);
}
@@ -2085,7 +2123,11 @@
/** @hide */
public void clearSubscriptionInfo() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.clearSubInfo();
}
@@ -2221,7 +2263,11 @@
*/
public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
int[] subId = iSub.getActiveSubIdList(visibleOnly);
if (subId != null) return subId;
@@ -2272,7 +2318,11 @@
int simState = TelephonyManager.SIM_STATE_UNKNOWN;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
simState = iSub.getSimStateForSlotIndex(slotIndex);
}
@@ -2291,7 +2341,11 @@
*/
public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setSubscriptionProperty(subId, propKey, propValue);
}
@@ -2311,7 +2365,11 @@
Context context) {
String resultValue = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
resultValue = iSub.getSubscriptionProperty(subId, propKey,
context.getOpPackageName(), context.getFeatureId());
@@ -2453,7 +2511,11 @@
@UnsupportedAppUsage
public boolean isActiveSubId(int subId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -2756,7 +2818,11 @@
@TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) {
if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) return;
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -2799,7 +2865,11 @@
public int getPreferredDataSubscriptionId() {
int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
preferredSubId = iSub.getPreferredDataSubscriptionId();
}
@@ -2830,7 +2900,11 @@
List<SubscriptionInfo> subInfoList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
}
@@ -2931,7 +3005,11 @@
ParcelUuid groupUuid = null;
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
} else {
@@ -2981,7 +3059,11 @@
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3033,7 +3115,11 @@
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3078,7 +3164,11 @@
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
} else {
@@ -3191,7 +3281,11 @@
logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.setSubscriptionEnabled(enable, subscriptionId);
}
@@ -3221,7 +3315,11 @@
logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setUiccApplicationsEnabled(enabled, subscriptionId);
}
@@ -3251,7 +3349,11 @@
logd("canDisablePhysicalSubscription");
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.canDisablePhysicalSubscription();
}
@@ -3272,7 +3374,11 @@
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isSubscriptionEnabled(int subscriptionId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isSubscriptionEnabled(subscriptionId);
}
@@ -3295,7 +3401,11 @@
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getEnabledSubscriptionId(slotIndex);
}
@@ -3321,7 +3431,11 @@
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = helper.callMethod(iSub);
}
@@ -3344,7 +3458,11 @@
*/
public static int getActiveDataSubscriptionId() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.getActiveDataSubscriptionId();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index df8c26d..607450b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,7 +60,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
@@ -107,6 +106,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.SmsApplication;
+import com.android.telephony.Rlog;
import dalvik.system.VMRuntime;
@@ -785,30 +785,6 @@
public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
/**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN type.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY;
-
- /**
* Broadcast intent action for letting the default dialer to know to show voicemail
* notification.
*
@@ -5107,7 +5083,11 @@
@UnsupportedAppUsage
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
- return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
+ return IPhoneSubInfo.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPhoneSubServiceRegisterer()
+ .get());
}
/**
@@ -5320,11 +5300,19 @@
}
private ITelephonyRegistry getTelephonyRegistry() {
- return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+ return ITelephonyRegistry.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRegistryServiceRegisterer()
+ .get());
}
private IOns getIOns() {
- return IOns.Stub.asInterface(ServiceManager.getService("ions"));
+ return IOns.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getOpportunisticNetworkServiceRegisterer()
+ .get());
}
//
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 96b6db7..8e6c170 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -19,7 +19,6 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -29,7 +28,6 @@
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.SparseArray;
import com.android.internal.telephony.ITelephony;
@@ -234,6 +232,9 @@
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 994c49c..e16fffa 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -21,8 +21,8 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.euicc.EuiccProfileInfo;
+import android.telephony.TelephonyFrameworkInitializer;
import android.util.Log;
import com.android.internal.telephony.euicc.IAuthenticateServerCallback;
@@ -148,7 +148,10 @@
private IEuiccCardController getIEuiccCardController() {
return IEuiccCardController.Stub.asInterface(
- ServiceManager.getService("euicc_card_controller"));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccCardControllerServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cb66a96..d5a48df 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,7 +30,7 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccCardManager.ResetOption;
@@ -968,6 +968,10 @@
}
private static IEuiccController getIEuiccController() {
- return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
+ return IEuiccController.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccControllerService()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 057d22c..91514e9 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,14 +25,13 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
@@ -1018,7 +1017,10 @@
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index d3fb37f..4f0f089 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -26,8 +26,8 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.feature.ImsFeature;
@@ -362,7 +362,10 @@
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index e4d6335..f052180 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -25,14 +25,13 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
-import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsConfigCallback;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
@@ -415,7 +414,11 @@
}
private static boolean isImsAvailableOnDevice() {
- IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPackageManagerServiceRegisterer()
+ .get());
if (pm == null) {
// For some reason package manger is not available.. This will fail internally anyways,
// so do not throw error and allow.
@@ -432,7 +435,10 @@
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java
index ce03c3c..1e93437 100644
--- a/telephony/java/android/telephony/ims/RcsControllerCall.java
+++ b/telephony/java/android/telephony/ims/RcsControllerCall.java
@@ -18,7 +18,7 @@
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IRcsMessage;
/**
@@ -35,8 +35,11 @@
}
<R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException {
- IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(ServiceManager.getService(
- Context.TELEPHONY_RCS_MESSAGE_SERVICE));
+ IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRcsMessageServiceRegisterer()
+ .get());
if (iRcsMessage == null) {
throw new RcsMessageStoreException("Could not connect to RCS storage service");
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 75e3f0a..2e3f59a 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,12 +21,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.content.Context;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.util.Log;
@@ -365,7 +364,10 @@
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/com/android/telephony/Rlog.java b/telephony/java/com/android/telephony/Rlog.java
new file mode 100644
index 0000000..9d6c930
--- /dev/null
+++ b/telephony/java/com/android/telephony/Rlog.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 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.telephony;
+
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.internal.telephony.util.TelephonyUtils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * A copy of {@link android.telephony.Rlog} to be used within the telephony mainline module.
+ *
+ * @hide
+ */
+public final class Rlog {
+
+ private static final boolean USER_BUILD = TelephonyUtils.IS_USER;
+
+ private Rlog() {
+ }
+
+ private static int log(int priority, String tag, String msg) {
+ return Log.logToRadioBuffer(priority, tag, msg);
+ }
+
+ public static int v(String tag, String msg) {
+ return log(Log.VERBOSE, tag, msg);
+ }
+
+ public static int v(String tag, String msg, Throwable tr) {
+ return log(Log.VERBOSE, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int d(String tag, String msg) {
+ return log(Log.DEBUG, tag, msg);
+ }
+
+ public static int d(String tag, String msg, Throwable tr) {
+ return log(Log.DEBUG, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int i(String tag, String msg) {
+ return log(Log.INFO, tag, msg);
+ }
+
+ public static int i(String tag, String msg, Throwable tr) {
+ return log(Log.INFO, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, String msg) {
+ return log(Log.WARN, tag, msg);
+ }
+
+ public static int w(String tag, String msg, Throwable tr) {
+ return log(Log.WARN, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, Throwable tr) {
+ return log(Log.WARN, tag, Log.getStackTraceString(tr));
+ }
+
+ public static int e(String tag, String msg) {
+ return log(Log.ERROR, tag, msg);
+ }
+
+ public static int e(String tag, String msg, Throwable tr) {
+ return log(Log.ERROR, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int println(int priority, String tag, String msg) {
+ return log(priority, tag, msg);
+ }
+
+ public static boolean isLoggable(String tag, int level) {
+ return Log.isLoggable(tag, level);
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param tag used to identify the source of a log message
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If tag is loggable in verbose mode or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(String tag, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If enablePiiLogging is set to true or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(boolean enablePiiLogging, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+ *
+ * @return "****" if the build type is user, otherwise the hash
+ * @param input the bytes for which the secure hash should be computed.
+ */
+ private static String secureHash(byte[] input) {
+ // Refrain from logging user personal information in user build.
+ if (USER_BUILD) {
+ return "****";
+ }
+
+ MessageDigest messageDigest;
+
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ return "####";
+ }
+
+ byte[] result = messageDigest.digest(input);
+ return Base64.encodeToString(
+ result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 40169b8..9e490f7 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -324,6 +324,7 @@
@Test
public void testNetworkPassedDoesNotRollback_Phase1() throws Exception {
+ // Remove available rollbacks and uninstall NetworkStack on /data/
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
@@ -332,6 +333,15 @@
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
+
+ // Reduce health check deadline, here unlike the network failed case, we use
+ // a longer deadline because joining a network can take a much longer time for
+ // reasons external to the device than 'not joining'
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
+ Integer.toString(300000), false);
+ // Simulate re-installation of new NetworkStack with rollbacks enabled
+ installNetworkStackPackage();
}
@Test
@@ -343,6 +353,9 @@
@Test
public void testNetworkPassedDoesNotRollback_Phase3() throws Exception {
+ // Sleep for > health check deadline. We expect no rollback should happen during sleeping.
+ // If the device reboots for rollback, this device test will fail as well as the host test.
+ Thread.sleep(TimeUnit.SECONDS.toMillis(310));
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
getNetworkStackPackageName())).isNull();
@@ -380,11 +393,6 @@
}
@Test
- public void testRollbackWhitelistedApp_cleanUp() throws Exception {
- RollbackUtils.getRollbackManager().expireRollbackForPackage(getModuleMetadataPackageName());
- }
-
- @Test
public void testRollbackDataPolicy_Phase1() throws Exception {
Uninstall.packages(TestApp.A, TestApp.B);
Install.multi(TestApp.A1, TestApp.B1).commit();
@@ -422,6 +430,16 @@
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
}
+ @Test
+ public void testCleanUp() throws Exception {
+ // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
+ // committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
+ // so there is only one rollback to commit when testing native crashes.
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ }
+
private static void runShellCommand(String cmd) {
ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 4644d8a..91577c2 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -22,8 +22,8 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +53,11 @@
getDevice().reboot();
}
+ @After
+ public void tearDown() throws Exception {
+ runPhase("testCleanUp");
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@@ -128,21 +133,8 @@
* Tests passed network health check does not trigger watchdog staged rollbacks.
*/
@Test
- @Ignore("b/143514090")
public void testNetworkPassedDoesNotRollback() throws Exception {
- // Remove available rollbacks and uninstall NetworkStack on /data/
runPhase("testNetworkPassedDoesNotRollback_Phase1");
- // Reduce health check deadline, here unlike the network failed case, we use
- // a longer deadline because joining a network can take a much longer time for
- // reasons external to the device than 'not joining'
- getDevice().executeShellCommand("device_config put rollback "
- + "watchdog_request_timeout_millis 300000");
- // Simulate re-installation of new NetworkStack with rollbacks enabled
- getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
- + getNetworkStackPath());
-
- // Sleep to allow writes to disk before reboot
- Thread.sleep(5000);
// Reboot device to activate staged package
getDevice().reboot();
@@ -157,8 +149,6 @@
// on mobile data
getDevice().waitForDeviceAvailable();
- // Sleep for > health check deadline
- Thread.sleep(310000);
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
}
@@ -180,16 +170,9 @@
*/
@Test
public void testRollbackWhitelistedApp() throws Exception {
- try {
- runPhase("testRollbackWhitelistedApp_Phase1");
- getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
- } finally {
- // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
- // committed on a device which doesn't support checkpoint. Let's clean up the rollback
- // so there is only one rollback to commit when testing native crashes.
- runPhase("testRollbackWhitelistedApp_cleanUp");
- }
+ runPhase("testRollbackWhitelistedApp_Phase1");
+ getDevice().reboot();
+ runPhase("testRollbackWhitelistedApp_Phase2");
}
@Test
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 634f674..09d5386 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -106,8 +106,10 @@
name: "framework-wifi-test-defaults",
sdk_version: "core_platform", // tests can use @CorePlatformApi's
libs: [
+ // order matters: classes in framework-wifi are resolved before framework, meaning
+ // @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
"framework-wifi",
- "framework-minus-apex",
+ "framework",
// if sdk_version="" this gets automatically included, but here we need to add manually.
"framework-res",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1678d5a..71942f0 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -90,6 +90,8 @@
void allowAutojoin(int netId, boolean choice);
+ void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+
boolean startScan(String packageName, String featureId);
List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a379c75..f4c5b91 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -253,9 +253,12 @@
/** LEAP/Network EAP (only used with LEAP) */
public static final int LEAP = 2;
+ /** SAE (Used only for WPA3-Personal) */
+ public static final int SAE = 3;
+
public static final String varName = "auth_alg";
- public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
+ public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
}
/**
@@ -468,10 +471,13 @@
break;
case SECURITY_TYPE_SAE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
// Note: allowedSuiteBCiphers bitset will be set by the service once the
@@ -480,6 +486,8 @@
break;
case SECURITY_TYPE_OWE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_WAPI_PSK:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 378c67b..e870481 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -545,15 +545,22 @@
public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
/**
- * The look up key for an int that indicates why softAP started failed
- * currently support general and no_channel
- * @see #SAP_START_FAILURE_GENERAL
- * @see #SAP_START_FAILURE_NO_CHANNEL
- * @see #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION
+ * An extra containing the int error code for Soft AP start failure.
+ * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
+ * {@link android.content.Intent#getIntExtra}.
+ * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
+ * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
+ *
+ * The error code will be one of:
+ * {@link #SAP_START_FAILURE_GENERAL},
+ * {@link #SAP_START_FAILURE_NO_CHANNEL},
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_FAILURE_REASON =
+ "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
/**
* The previous Wi-Fi state.
*
@@ -4103,6 +4110,23 @@
}
/**
+ * Configure auto-join settings for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enableAutoJoin true to enable autojoin, false to disable autojoin.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinPasspoint(@NonNull String fqdn, boolean enableAutoJoin) {
+ try {
+ mService.allowAutojoinPasspoint(fqdn, enableAutoJoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 5befb54..1822e84 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,6 +17,7 @@
package android.net.wifi.hotspot2;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.net.wifi.hotspot2.pps.Policy;
@@ -423,6 +424,41 @@
}
/**
+ * The auto-join configuration specifies whether or not the Passpoint Configuration is
+ * considered for auto-connection. If true then yes, if false then it isn't considered as part
+ * of auto-connection - but can still be manually connected to.
+ */
+ private boolean mIsAutoJoinEnabled = true;
+
+ /**
+ * Configures the auto-association status of this Passpoint configuration. A value of true
+ * indicates that the configuration will be considered for auto-connection, a value of false
+ * indicates that only manual connection will work - the framework will not auto-associate to
+ * this Passpoint network.
+ *
+ * @param autoJoinEnabled true to be considered for framework auto-connection, false otherwise.
+ * @hide
+ */
+ public void setAutoJoinEnabled(boolean autoJoinEnabled) {
+ mIsAutoJoinEnabled = autoJoinEnabled;
+ }
+
+ /**
+ * Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
+ * value of true indicates that auto-connection can happen, a value of false indicates that it
+ * cannot. However, even when auto-connection is not possible manual connection by the user is
+ * possible.
+ *
+ * @return the auto-join configuration: true for auto-connection (or join) enabled, false
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutoJoinEnabled() {
+ return mIsAutoJoinEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -464,6 +500,7 @@
mServiceFriendlyNames = source.mServiceFriendlyNames;
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
+ mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
}
@Override
@@ -493,6 +530,7 @@
(HashMap<String, String>) mServiceFriendlyNames);
dest.writeBundle(bundle);
dest.writeInt(mCarrierId);
+ dest.writeBoolean(mIsAutoJoinEnabled);
}
@Override
@@ -523,6 +561,7 @@
&& mUsageLimitDataLimit == that.mUsageLimitDataLimit
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
+ && mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -533,7 +572,7 @@
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled);
}
@Override
@@ -587,6 +626,7 @@
builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
}
builder.append("CarrierId:" + mCarrierId);
+ builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
return builder.toString();
}
@@ -692,6 +732,7 @@
"serviceFriendlyNames");
config.setServiceFriendlyNames(friendlyNamesMap);
config.mCarrierId = in.readInt();
+ config.mIsAutoJoinEnabled = in.readBoolean();
return config;
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index d58083c..d91efbc 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -182,6 +182,11 @@
}
@Override
+ public void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 909cfef..8689a38 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -16,6 +16,10 @@
package android.net.wifi;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -328,4 +332,57 @@
assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i));
}
}
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for SAE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSae() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_SAE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for OWE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForOwe() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_OWE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for Suite-B security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSuiteB() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.allowedGroupManagementCiphers
+ .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+ assertTrue(config.requirePMF);
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f9bd31d..5ac50a0 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1672,10 +1672,22 @@
@Test
public void testAllowAutojoin() throws Exception {
mWifiManager.allowAutojoin(1, true);
- verify(mWifiService).allowAutojoin(eq(1), eq(true));
+ verify(mWifiService).allowAutojoin(1, true);
}
/**
+ * Test behavior of {@link WifiManager#allowAutojoinPasspoint(String, boolean)}
+ * @throws Exception
+ */
+ @Test
+ public void testAllowAutojoinPasspoint() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.allowAutojoinPasspoint(fqdn, true);
+ verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
+ }
+
+
+ /**
* Test behavior of {@link WifiManager#disconnect()}
*/
@Test
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index f501b16..94054fd 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -171,6 +171,7 @@
assertFalse(config.validate());
assertFalse(config.validateForR2());
+ assertTrue(config.isAutoJoinEnabled());
}
/**