Merge "Call TrustManager#reportUserRequestedUnlock"
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 4de8ec8..dd102bd 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -892,7 +892,8 @@
}
if (history.bucketExpiryTimesMs != null) {
xml.startTag(null, TAG_BUCKET_EXPIRY_TIMES);
- for (int j = 0; j < history.bucketExpiryTimesMs.size(); ++j) {
+ final int size = history.bucketExpiryTimesMs.size();
+ for (int j = 0; j < size; ++j) {
final long expiryTimeMs = history.bucketExpiryTimesMs.valueAt(j);
// Skip writing to disk if the expiry time already elapsed.
if (expiryTimeMs < elapsedTimeMs) {
@@ -994,7 +995,8 @@
return;
}
idpw.print("(");
- for (int i = 0; i < appUsageHistory.bucketExpiryTimesMs.size(); ++i) {
+ final int size = appUsageHistory.bucketExpiryTimesMs.size();
+ for (int i = 0; i < size; ++i) {
final int bucket = appUsageHistory.bucketExpiryTimesMs.keyAt(i);
final long expiryTimeMs = appUsageHistory.bucketExpiryTimesMs.valueAt(i);
if (i != 0) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 776f374..4aee690 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -125,11 +125,13 @@
field public static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
+ field public static final String READ_ASSISTANT_APP_SEARCH_DATA = "android.permission.READ_ASSISTANT_APP_SEARCH_DATA";
field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE";
field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
field public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
+ field public static final String READ_HOME_APP_SEARCH_DATA = "android.permission.READ_HOME_APP_SEARCH_DATA";
field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final String READ_LOGS = "android.permission.READ_LOGS";
field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
@@ -8852,11 +8854,12 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering();
method public boolean isEnabled();
method public boolean isLe2MPhySupported();
+ method public int isLeAudioBroadcastAssistantSupported();
+ method public int isLeAudioBroadcastSourceSupported();
method public int isLeAudioSupported();
method public boolean isLeCodedPhySupported();
method public boolean isLeExtendedAdvertisingSupported();
method public boolean isLePeriodicAdvertisingSupported();
- method public int isLePeriodicAdvertisingSyncTransferSenderSupported();
method public boolean isMultipleAdvertisementSupported();
method public boolean isOffloadedFilteringSupported();
method public boolean isOffloadedScanBatchingSupported();
@@ -9758,6 +9761,7 @@
field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
field public static final int GATT = 7; // 0x7
field public static final int GATT_SERVER = 8; // 0x8
+ field public static final int HAP_CLIENT = 28; // 0x1c
field public static final int HEADSET = 1; // 0x1
field @Deprecated public static final int HEALTH = 3; // 0x3
field public static final int HEARING_AID = 21; // 0x15
@@ -10933,10 +10937,10 @@
method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
+ method public void revokeOwnPermissionOnKill(@NonNull String);
+ method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
- method public void selfRevokePermission(@NonNull String);
- method public void selfRevokePermissions(@NonNull java.util.Collection<java.lang.String>);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -11064,8 +11068,8 @@
field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
field public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
- field public static final String TV_IAPP_SERVICE = "tv_iapp";
field public static final String TV_INPUT_SERVICE = "tv_input";
+ field public static final String TV_INTERACTIVE_APP_SERVICE = "tv_interactive_app";
field public static final String UI_MODE_SERVICE = "uimode";
field public static final String USAGE_STATS_SERVICE = "usagestats";
field public static final String USB_SERVICE = "usb";
@@ -18051,6 +18055,7 @@
field public static final long USAGE_CPU_READ_RARELY = 2L; // 0x2L
field public static final long USAGE_CPU_WRITE_OFTEN = 48L; // 0x30L
field public static final long USAGE_CPU_WRITE_RARELY = 32L; // 0x20L
+ field public static final long USAGE_FRONT_BUFFER = 1L; // 0x1L
field public static final long USAGE_GPU_COLOR_OUTPUT = 512L; // 0x200L
field public static final long USAGE_GPU_CUBE_MAP = 33554432L; // 0x2000000L
field public static final long USAGE_GPU_DATA_BUFFER = 16777216L; // 0x1000000L
@@ -22077,14 +22082,30 @@
public class ImageWriter implements java.lang.AutoCloseable {
method public void close();
method public android.media.Image dequeueInputImage();
+ method public long getDataSpace();
method public int getFormat();
+ method public int getHardwareBufferFormat();
+ method public int getHeight();
method public int getMaxImages();
+ method public long getUsage();
+ method public int getWidth();
method @NonNull public static android.media.ImageWriter newInstance(@NonNull android.view.Surface, @IntRange(from=1) int);
method @NonNull public static android.media.ImageWriter newInstance(@NonNull android.view.Surface, @IntRange(from=1) int, int);
method public void queueInputImage(android.media.Image);
method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
}
+ public static final class ImageWriter.Builder {
+ ctor public ImageWriter.Builder(@NonNull android.view.Surface);
+ method @NonNull public android.media.ImageWriter build();
+ method @NonNull public android.media.ImageWriter.Builder setDataSpace(long);
+ method @NonNull public android.media.ImageWriter.Builder setHardwareBufferFormat(int);
+ method @NonNull public android.media.ImageWriter.Builder setImageFormat(int);
+ method @NonNull public android.media.ImageWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method @NonNull public android.media.ImageWriter.Builder setUsage(long);
+ method @NonNull public android.media.ImageWriter.Builder setWidthAndHeight(@IntRange(from=1) int, @IntRange(from=1) int);
+ }
+
public static interface ImageWriter.OnImageReleasedListener {
method public void onImageReleased(android.media.ImageWriter);
}
@@ -22496,6 +22517,7 @@
field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+ field public static final String FEATURE_EncodingStatistics = "encoding-statistics";
field public static final String FEATURE_FrameParsing = "frame-parsing";
field public static final String FEATURE_IntraRefresh = "intra-refresh";
field public static final String FEATURE_LowLatency = "low-latency";
@@ -23270,6 +23292,7 @@
field public static final String KEY_OPERATING_RATE = "operating-rate";
field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+ field public static final String KEY_PICTURE_TYPE = "picture-type";
field public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height";
field public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width";
field public static final String KEY_PREPEND_HEADER_TO_SYNC_FRAMES = "prepend-sps-pps-to-idr-frames";
@@ -23287,6 +23310,8 @@
field public static final String KEY_TILE_HEIGHT = "tile-height";
field public static final String KEY_TILE_WIDTH = "tile-width";
field public static final String KEY_TRACK_ID = "track-id";
+ field public static final String KEY_VIDEO_ENCODING_STATISTICS_LEVEL = "video-encoding-statistics-level";
+ field public static final String KEY_VIDEO_QP_AVERAGE = "video-qp-average";
field public static final String KEY_VIDEO_QP_B_MAX = "video-qp-b-max";
field public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
field public static final String KEY_VIDEO_QP_I_MAX = "video-qp-i-max";
@@ -23347,12 +23372,18 @@
field public static final String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
field public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
field public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+ field public static final int PICTURE_TYPE_B = 3; // 0x3
+ field public static final int PICTURE_TYPE_I = 1; // 0x1
+ field public static final int PICTURE_TYPE_P = 2; // 0x2
+ field public static final int PICTURE_TYPE_UNKNOWN = 0; // 0x0
field public static final int TYPE_BYTE_BUFFER = 5; // 0x5
field public static final int TYPE_FLOAT = 3; // 0x3
field public static final int TYPE_INTEGER = 1; // 0x1
field public static final int TYPE_LONG = 2; // 0x2
field public static final int TYPE_NULL = 0; // 0x0
field public static final int TYPE_STRING = 4; // 0x4
+ field public static final int VIDEO_ENCODING_STATISTICS_LEVEL_1 = 1; // 0x1
+ field public static final int VIDEO_ENCODING_STATISTICS_LEVEL_NONE = 0; // 0x0
}
public final class MediaMetadata implements android.os.Parcelable {
@@ -26849,16 +26880,43 @@
package android.media.tv.interactive {
- public final class TvIAppManager {
+ public final class TvInteractiveAppInfo implements android.os.Parcelable {
+ ctor public TvInteractiveAppInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+ method public int describeContents();
+ method @NonNull public String getId();
+ method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
+ method @NonNull public int getSupportedTypes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppInfo> CREATOR;
+ field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
+ field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
+ field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
}
- public abstract class TvIAppService extends android.app.Service {
- ctor public TvIAppService();
+ public final class TvInteractiveAppManager {
+ method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
+ }
+
+ public abstract class TvInteractiveAppService extends android.app.Service {
+ ctor public TvInteractiveAppService();
method public final android.os.IBinder onBind(android.content.Intent);
- field public static final String SERVICE_INTERFACE = "android.media.tv.interactive.TvIAppService";
+ field public static final String SERVICE_INTERFACE = "android.media.tv.interactive.TvInteractiveAppService";
field public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
}
+ public class TvInteractiveAppView extends android.view.ViewGroup {
+ ctor public TvInteractiveAppView(@NonNull android.content.Context);
+ ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+ ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int);
+ method public void clearCallback();
+ method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
+ method public void startInteractiveApp();
+ }
+
+ public abstract static class TvInteractiveAppView.TvInteractiveAppCallback {
+ ctor public TvInteractiveAppView.TvInteractiveAppCallback();
+ }
+
}
package android.mtp {
@@ -32236,7 +32294,7 @@
method @Deprecated public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
method public <K, V> void readMap(@NonNull java.util.Map<? super K,? super V>, @Nullable ClassLoader, @NonNull Class<K>, @NonNull Class<V>);
method @Deprecated @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
- method @Nullable public <T> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
+ method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<? super T>);
method @Deprecated @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>);
method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
@@ -32246,7 +32304,7 @@
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
method @Deprecated @Nullable public java.io.Serializable readSerializable();
- method @Nullable public <T> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
+ method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<? super T>);
method @NonNull public android.util.Size readSize();
method @NonNull public android.util.SizeF readSizeF();
method @Deprecated @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
@@ -32516,6 +32574,7 @@
method public static final boolean is64Bit();
method public static boolean isApplicationUid(int);
method public static final boolean isIsolated();
+ method public static final boolean isSupplemental();
method public static final void killProcess(int);
method public static final int myPid();
method @NonNull public static String myProcessName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index fe53e63..b082629 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -389,6 +389,9 @@
}
public class Process {
+ method public static final boolean isSupplemental(int);
+ method public static final int toAppUid(int);
+ method public static final int toSupplementalUid(int);
field public static final int NFC_UID = 1027; // 0x403
field public static final int VPN_UID = 1016; // 0x3f8
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 465c1f8..cf20b4c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1064,6 +1064,7 @@
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
+ field @RequiresPermission(android.Manifest.permission.DISPATCH_PROVISIONING_MESSAGE) public static final String ACTION_ESTABLISH_NETWORK_CONNECTION = "android.app.action.ESTABLISH_NETWORK_CONNECTION";
field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
field public static final String ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE";
field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
@@ -2238,6 +2239,7 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isEncrypted();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setLowLatencyAudioAllowed(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMessageAccessPermission(int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setPhonebookAccessPermission(int);
@@ -2387,6 +2389,7 @@
field @NonNull public static final android.os.ParcelUuid COORDINATED_SET;
field @NonNull public static final android.os.ParcelUuid DIP;
field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL;
+ field @NonNull public static final android.os.ParcelUuid HAS;
field @NonNull public static final android.os.ParcelUuid HEARING_AID;
field @NonNull public static final android.os.ParcelUuid HFP;
field @NonNull public static final android.os.ParcelUuid HFP_AG;
@@ -2603,10 +2606,32 @@
package android.companion.virtual {
public final class VirtualDeviceManager {
+ method @Nullable @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
}
public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
method public void close();
+ method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(int, int, int, @Nullable android.view.Surface, int, @Nullable android.os.Handler, @Nullable android.hardware.display.VirtualDisplay.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+ }
+
+ public final class VirtualDeviceParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLockState();
+ method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
+ field public static final int LOCK_STATE_ALWAYS_LOCKED = 0; // 0x0
+ field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
+ }
+
+ public static final class VirtualDeviceParams.Builder {
+ ctor public VirtualDeviceParams.Builder();
+ method @NonNull public android.companion.virtual.VirtualDeviceParams build();
+ method @NonNull @RequiresPermission(value="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY", conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
+ method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
}
}
@@ -3660,6 +3685,7 @@
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
+ field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
}
@@ -6594,6 +6620,7 @@
method @Nullable public android.media.tv.tuner.Lnb openLnbByName(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_SHARED_FILTER) public static android.media.tv.tuner.filter.SharedFilter openSharedFilter(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.filter.SharedFilterCallback);
method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
+ method public int removeOutputPid(@IntRange(from=0) int);
method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
method public int setLnaEnabled(boolean);
method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int);
@@ -9697,9 +9724,9 @@
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
+ method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
- method @BinderThread public void onSelfRevokePermissions(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
@@ -11069,6 +11096,7 @@
method @android.service.persistentdata.PersistentDataBlockManager.FlashLockState @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public int getFlashLockState();
method public long getMaximumDataBlockSize();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public boolean getOemUnlockEnabled();
+ method @NonNull public String getPersistentDataPackageName();
method public byte[] read();
method @Deprecated @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void setOemUnlockEnabled(boolean);
method @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void wipe();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0e52c5d..e97ef6c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1928,6 +1928,9 @@
method @NonNull public static String convert(@NonNull java.util.UUID);
method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
method public static boolean isUserKeyUnlocked(int);
+ field public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
+ field public static final String CACHE_RESERVE_PERCENT_LOW_KEY = "cache_reserve_percent_low";
+ field public static final String STORAGE_THRESHOLD_PERCENT_HIGH_KEY = "storage_threshold_percent_high";
}
public final class StorageVolume implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/TouchInteractionController.java b/core/java/android/accessibilityservice/TouchInteractionController.java
index a8ba1d3..bb2b8d4 100644
--- a/core/java/android/accessibilityservice/TouchInteractionController.java
+++ b/core/java/android/accessibilityservice/TouchInteractionController.java
@@ -24,6 +24,8 @@
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityInteractionClient;
+import java.util.LinkedList;
+import java.util.Queue;
import java.util.concurrent.Executor;
/**
@@ -102,6 +104,11 @@
private boolean mServiceDetectsGestures;
/** Map of callbacks to executors. Lazily created when adding the first callback. */
private ArrayMap<Callback, Executor> mCallbacks;
+ // A list of motion events that should be queued until a pending transition has taken place.
+ private Queue<MotionEvent> mQueuedMotionEvents = new LinkedList<>();
+ // Whether this controller is waiting for a state transition.
+ // Motion events will be queued and sent to listeners after the transition has taken place.
+ private boolean mStateChangeRequested = false;
// The current state of the display.
private int mState = STATE_CLEAR;
@@ -169,6 +176,14 @@
* main thread.
*/
void onMotionEvent(MotionEvent event) {
+ if (mStateChangeRequested) {
+ mQueuedMotionEvents.add(event);
+ } else {
+ sendEventToAllListeners(event);
+ }
+ }
+
+ private void sendEventToAllListeners(MotionEvent event) {
final ArrayMap<Callback, Executor> entries;
synchronized (mLock) {
// callbacks may remove themselves. Perform a shallow copy to avoid concurrent
@@ -209,6 +224,10 @@
callback.onStateChanged(state);
}
}
+ mStateChangeRequested = false;
+ while (mQueuedMotionEvents.size() > 0) {
+ sendEventToAllListeners(mQueuedMotionEvents.poll());
+ }
}
/**
@@ -253,6 +272,7 @@
} catch (RemoteException re) {
throw new RuntimeException(re);
}
+ mStateChangeRequested = true;
}
}
@@ -281,6 +301,7 @@
} catch (RemoteException re) {
throw new RuntimeException(re);
}
+ mStateChangeRequested = true;
}
}
@@ -302,6 +323,7 @@
} catch (RemoteException re) {
throw new RuntimeException(re);
}
+ mStateChangeRequested = true;
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fa48730..f3315a8 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2179,8 +2179,8 @@
}
@Override
- public void selfRevokePermissions(@NonNull Collection<String> permissions) {
- getSystemService(PermissionManager.class).selfRevokePermissions(permissions);
+ public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
}
@Override
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index a9ec11e..0801b24 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -72,6 +72,7 @@
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter;
import android.window.IWindowOrganizerController;
+import android.window.BackNavigationInfo;
import android.window.SplashScreenView;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
@@ -346,7 +347,8 @@
void setRunningRemoteTransitionDelegate(in IApplicationThread caller);
/**
- * Prepare the back preview in the server
+ * Prepare the back navigation in the server. This setups the leashed for sysui to animate
+ * the back gesture and returns the data needed for the animation.
*/
- void startBackPreview(IRemoteAnimationRunner runner);
+ android.window.BackNavigationInfo startBackNavigation();
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 67c42f6..63c1fd8 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -124,8 +124,8 @@
import android.media.soundtrigger.SoundTriggerManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
-import android.media.tv.interactive.ITvIAppManager;
-import android.media.tv.interactive.TvIAppManager;
+import android.media.tv.interactive.ITvInteractiveAppManager;
+import android.media.tv.interactive.TvInteractiveAppManager;
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.nearby.NearbyFrameworkInitializer;
@@ -964,13 +964,16 @@
}
});
- registerService(Context.TV_IAPP_SERVICE, TvIAppManager.class,
- new CachedServiceFetcher<TvIAppManager>() {
+ registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class,
+ new CachedServiceFetcher<TvInteractiveAppManager>() {
@Override
- public TvIAppManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder iBinder = ServiceManager.getServiceOrThrow(Context.TV_IAPP_SERVICE);
- ITvIAppManager service = ITvIAppManager.Stub.asInterface(iBinder);
- return new TvIAppManager(service, ctx.getUserId());
+ public TvInteractiveAppManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder iBinder =
+ ServiceManager.getServiceOrThrow(Context.TV_INTERACTIVE_APP_SERVICE);
+ ITvInteractiveAppManager service =
+ ITvInteractiveAppManager.Stub.asInterface(iBinder);
+ return new TvInteractiveAppManager(service, ctx.getUserId());
}});
registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
@@ -1021,19 +1024,21 @@
}});
registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
- new StaticServiceFetcher<PersistentDataBlockManager>() {
+ new CachedServiceFetcher<PersistentDataBlockManager>() {
@Override
- public PersistentDataBlockManager createService() throws ServiceNotFoundException {
+ public PersistentDataBlockManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.PERSISTENT_DATA_BLOCK_SERVICE);
IPersistentDataBlockService persistentDataBlockService =
IPersistentDataBlockService.Stub.asInterface(b);
if (persistentDataBlockService != null) {
- return new PersistentDataBlockManager(persistentDataBlockService);
+ return new PersistentDataBlockManager(ctx, persistentDataBlockService);
} else {
// not supported
return null;
}
- }});
+ }
+ });
registerService(Context.OEM_LOCK_SERVICE, OemLockManager.class,
new StaticServiceFetcher<OemLockManager>() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8415794..cefd25a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3012,6 +3012,54 @@
"android.app.extra.PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT";
/**
+ * Activity action: attempts to establish network connection
+ *
+ * <p>This intent can be accompanied by any of the relevant provisioning extras related to
+ * network connectivity, such as:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_SSID}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_HIDDEN}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_SECURITY_TYPE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PASSWORD}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}</li>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_EAP_METHOD}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_PHASE2_AUTH}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_IDENTITY}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY}</li>
+ * <li>{@code #EXTRA_PROVISIONING_WIFI_DOMAIN}</li>
+ * </ul>
+ *
+ * <p>If there are provisioning extras related to network connectivity, this activity
+ * attempts to connect to the specified network. Otherwise it prompts the end-user to connect.
+ *
+ * <p>This activity is meant to be started by the provisioning initiator prior to starting
+ * {@link #ACTION_PROVISION_MANAGED_PROFILE} or {@link
+ * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}.
+ *
+ * <p>Note that network connectivity is still also handled when provisioning via {@link
+ * #ACTION_PROVISION_MANAGED_PROFILE} or {@link
+ * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}. {@link
+ * #ACTION_ESTABLISH_NETWORK_CONNECTION} should only be used in cases when the provisioning
+ * initiator would like to do some additional logic after the network connectivity step and
+ * before the start of provisioning.
+ *
+ * If network connection is established, {@link Activity#RESULT_OK} will be returned. Otherwise
+ * the result will be {@link Activity#RESULT_CANCELED}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DISPATCH_PROVISIONING_MESSAGE)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @SystemApi
+ public static final String ACTION_ESTABLISH_NETWORK_CONNECTION =
+ "android.app.action.ESTABLISH_NETWORK_CONNECTION";
+
+ /**
* Maximum supported password length. Kind-of arbitrary.
* @hide
*/
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 8ab6688..a97b7b3 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -16,7 +16,6 @@
package android.companion.virtual;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -43,10 +42,6 @@
import android.os.ResultReceiver;
import android.view.Surface;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import java.util.concurrent.Executor;
/**
@@ -61,23 +56,6 @@
private static final boolean DEBUG = false;
private static final String LOG_TAG = "VirtualDeviceManager";
- /** @hide */
- @IntDef(prefix = "DISPLAY_FLAG_",
- flag = true,
- value = {DISPLAY_FLAG_TRUSTED})
- @Retention(RetentionPolicy.SOURCE)
- @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
- public @interface DisplayFlags {}
-
- /**
- * Indicates that the display is trusted to show system decorations and receive inputs without
- * users' touch.
- *
- * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
- * @hide // TODO(b/194949534): Unhide this API
- */
- public static final int DISPLAY_FLAG_TRUSTED = 1;
-
private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
@@ -102,12 +80,12 @@
* @param associationId The association ID as returned by {@link AssociationInfo#getId()} from
* Companion Device Manager. Virtual devices must have a corresponding association with CDM in
* order to be created.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Nullable
- public VirtualDevice createVirtualDevice(int associationId, VirtualDeviceParams params) {
- // TODO(b/194949534): Unhide this API
+ public VirtualDevice createVirtualDevice(
+ int associationId,
+ @NonNull VirtualDeviceParams params) {
try {
IVirtualDevice virtualDevice = mService.createVirtualDevice(
new Binder(), mContext.getPackageName(), associationId, params);
@@ -187,7 +165,12 @@
* @param surface The surface to which the content of the virtual display should
* be rendered, or null if there is none initially. The surface can also be set later using
* {@link VirtualDisplay#setSurface(Surface)}.
- * @param flags Either 0, or {@link #DISPLAY_FLAG_TRUSTED}.
+ * @param flags A combination of virtual display flags accepted by
+ * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are
+ * automatically set for all virtual devices:
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
* @param callback Callback to call when the state of the {@link VirtualDisplay} changes
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
@@ -195,9 +178,7 @@
* not create the virtual display.
*
* @see DisplayManager#createVirtualDisplay
- * @hide
*/
- // TODO(b/194949534): Unhide this API
// Suppress "ExecutorRegistration" because DisplayManager.createVirtualDisplay takes a
// handler
@SuppressLint("ExecutorRegistration")
@@ -207,7 +188,7 @@
int height,
int densityDpi,
@Nullable Surface surface,
- @DisplayFlags int flags,
+ int flags,
@Nullable Handler handler,
@Nullable VirtualDisplay.Callback callback) {
// TODO(b/205343547): Handle display groups properly instead of creating a new display
@@ -246,7 +227,6 @@
* @param inputDeviceName the name to call this input device
* @param vendorId the vendor id
* @param productId the product id
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -273,7 +253,6 @@
* @param inputDeviceName the name to call this input device
* @param vendorId the vendor id
* @param productId the product id
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -300,7 +279,6 @@
* @param inputDeviceName the name to call this input device
* @param vendorId the vendor id
* @param productId the product id
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -328,12 +306,8 @@
* com.android.server.companion.virtual.VirtualDeviceImpl#getBaseVirtualDisplayFlags()} will
* be added by DisplayManagerService.
*/
- private int getVirtualDisplayFlags(@DisplayFlags int flags) {
- int virtualDisplayFlags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
- if ((flags & DISPLAY_FLAG_TRUSTED) != 0) {
- virtualDisplayFlags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
- }
- return virtualDisplayFlags;
+ private int getVirtualDisplayFlags(int flags) {
+ return DEFAULT_VIRTUAL_DISPLAY_FLAGS | flags;
}
private String getVirtualDisplayName() {
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 169f4e1..2ddfeb4 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,7 +42,7 @@
*
* @hide
*/
-// TODO(b/194949534): Unhide this API
+@SystemApi
public final class VirtualDeviceParams implements Parcelable {
/** @hide */
@@ -53,15 +54,11 @@
/**
* Indicates that the lock state of the virtual device should be always locked.
- *
- * @hide // TODO(b/194949534): Unhide this API
*/
public static final int LOCK_STATE_ALWAYS_LOCKED = 0;
/**
* Indicates that the lock state of the virtual device should be always unlocked.
- *
- * @hide // TODO(b/194949534): Unhide this API
*/
public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1;
@@ -112,6 +109,7 @@
* Returns the set of activities allowed to be streamed, or {@code null} if this is not set.
*
* @see Builder#setAllowedActivities(Set)
+ * @hide // TODO(b/194949534): Unhide this API
*/
@Nullable
public Set<ComponentName> getAllowedActivities() {
@@ -126,6 +124,7 @@
* set.
*
* @see Builder#setBlockedActivities(Set)
+ * @hide // TODO(b/194949534): Unhide this API
*/
@Nullable
public Set<ComponentName> getBlockedActivities() {
@@ -169,6 +168,7 @@
}
@Override
+ @NonNull
public String toString() {
return "VirtualDeviceParams("
+ " mLockState=" + mLockState
@@ -178,6 +178,7 @@
+ ")";
}
+ @NonNull
public static final Parcelable.Creator<VirtualDeviceParams> CREATOR =
new Parcelable.Creator<VirtualDeviceParams>() {
public VirtualDeviceParams createFromParcel(Parcel in) {
@@ -216,13 +217,25 @@
/**
* Sets the user handles with matching managed accounts on the remote device to which
- * this virtual device is streaming.
+ * this virtual device is streaming. The caller is responsible for verifying the presence
+ * and legitimacy of a matching managed account on the remote device.
+ *
+ * <p>If the app streaming policy is
+ * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
+ * NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY}, activities not in
+ * {@code usersWithMatchingAccounts} will be blocked from starting.
+ *
+ * <p> If {@code usersWithMatchingAccounts} is empty (the default), streaming is allowed
+ * only if there is no device policy, or if the nearby streaming policy is
+ * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_ENABLED
+ * NEARBY_STREAMING_ENABLED}.
*
* @param usersWithMatchingAccounts A set of user handles with matching managed
* accounts on the remote device this is streaming to.
*
* @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
*/
+ @NonNull
public Builder setUsersWithMatchingAccounts(
@NonNull Set<UserHandle> usersWithMatchingAccounts) {
mUsersWithMatchingAccounts = usersWithMatchingAccounts;
@@ -242,6 +255,7 @@
*
* @param allowedActivities A set of activity {@link ComponentName} allowed to be launched
* in the virtual device.
+ * @hide // TODO(b/194949534): Unhide this API
*/
public Builder setAllowedActivities(@Nullable Set<ComponentName> allowedActivities) {
if (mBlockedActivities != null && allowedActivities != null) {
@@ -265,6 +279,7 @@
*
* @param blockedActivities A set of {@link ComponentName} to be blocked launching from
* virtual device.
+ * @hide // TODO(b/194949534): Unhide this API
*/
public Builder setBlockedActivities(@Nullable Set<ComponentName> blockedActivities) {
if (mAllowedActivities != null && blockedActivities != null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2309fb6..845d23c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3829,7 +3829,7 @@
PRINT_SERVICE,
CONSUMER_IR_SERVICE,
//@hide: TRUST_SERVICE,
- TV_IAPP_SERVICE,
+ TV_INTERACTIVE_APP_SERVICE,
TV_INPUT_SERVICE,
//@hide: TV_TUNER_RESOURCE_MGR_SERVICE,
//@hide: NETWORK_SCORE_SERVICE,
@@ -5356,13 +5356,13 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.media.tv.interactive.TvIAppManager} for interacting with TV interactive
- * applications (TV iApp) on the device.
+ * {@link android.media.tv.interactive.TvInteractiveAppManager} for interacting with TV
+ * interactive applications on the device.
*
* @see #getSystemService(String)
- * @see android.media.tv.interactive.TvIAppManager
+ * @see android.media.tv.interactive.TvInteractiveAppManager
*/
- public static final String TV_IAPP_SERVICE = "tv_iapp";
+ public static final String TV_INTERACTIVE_APP_SERVICE = "tv_interactive_app";
/**
* Use with {@link #getSystemService(String)} to retrieve a
@@ -6417,10 +6417,10 @@
* Triggers the asynchronous revocation of a permission.
*
* @param permName The name of the permission to be revoked.
- * @see #selfRevokePermissions(Collection)
+ * @see #revokeOwnPermissionsOnKill(Collection)
*/
- public void selfRevokePermission(@NonNull String permName) {
- selfRevokePermissions(Collections.singletonList(permName));
+ public void revokeOwnPermissionOnKill(@NonNull String permName) {
+ revokeOwnPermissionsOnKill(Collections.singletonList(permName));
}
/**
@@ -6445,7 +6445,7 @@
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
*/
- public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+ public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 805e499..6ae768a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1016,8 +1016,8 @@
}
@Override
- public void selfRevokePermissions(@NonNull Collection<String> permissions) {
- mBase.selfRevokePermissions(permissions);
+ public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ mBase.revokeOwnPermissionsOnKill(permissions);
}
@Override
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 4683d25..acceb65 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -110,9 +110,9 @@
@Retention(RetentionPolicy.SOURCE)
@LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
- USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
- USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
- USAGE_GPU_MIPMAP_COMPLETE})
+ USAGE_GPU_COLOR_OUTPUT, USAGE_COMPOSER_OVERLAY, USAGE_PROTECTED_CONTENT,
+ USAGE_VIDEO_ENCODE, USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA,
+ USAGE_GPU_CUBE_MAP, USAGE_GPU_MIPMAP_COMPLETE, USAGE_FRONT_BUFFER})
public @interface Usage {};
@Usage
@@ -151,6 +151,12 @@
public static final long USAGE_GPU_CUBE_MAP = 1 << 25;
/** Usage: The buffer contains a complete mipmap hierarchy */
public static final long USAGE_GPU_MIPMAP_COMPLETE = 1 << 26;
+ /** Usage: The buffer is used for front-buffer rendering. When front-buffering rendering is
+ * specified, different usages may adjust their behavior as a result. For example, when
+ * used as USAGE_GPU_COLOR_OUTPUT the buffer will behave similar to a single-buffered window.
+ * When used with USAGE_COMPOSER_OVERLAY, the system will try to prioritize the buffer
+ * receiving an overlay plane & avoid caching it in intermediate composition buffers. */
+ public static final long USAGE_FRONT_BUFFER = 1 << 32;
/**
* Creates a new <code>HardwareBuffer</code> instance.
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 89ac8bf..eefa1d3 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -334,6 +334,7 @@
* @hide
*/
@TestApi
+ @SystemApi
public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
/**
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 3bc3ec8..e8b3ae9 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3711,10 +3711,10 @@
final int m = list.size();
int i = 0;
for (; i < m && i < n; i++) {
- list.set(i, (T) readParcelableInternal(cl, clazz));
+ list.set(i, readParcelableInternal(cl, clazz));
}
for (; i < n; i++) {
- list.add((T) readParcelableInternal(cl, clazz));
+ list.add(readParcelableInternal(cl, clazz));
}
for (; i < m; i++) {
list.remove(n);
@@ -4217,7 +4217,8 @@
* trying to instantiate an element.
*/
@Nullable
- public <T> T readParcelable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
+ @NonNull Class<? super T> clazz) {
Objects.requireNonNull(clazz);
return readParcelableInternal(loader, clazz);
}
@@ -4227,7 +4228,8 @@
*/
@SuppressWarnings("unchecked")
@Nullable
- private <T> T readParcelableInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ private <T extends Parcelable> T readParcelableInternal(@Nullable ClassLoader loader,
+ @Nullable Class<? super T> clazz) {
Parcelable.Creator<?> creator = readParcelableCreatorInternal(loader, clazz);
if (creator == null) {
return null;
@@ -4463,7 +4465,8 @@
* deserializing the object.
*/
@Nullable
- public <T> T readSerializable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader,
+ @NonNull Class<? super T> clazz) {
Objects.requireNonNull(clazz);
return readSerializableInternal(
loader == null ? getClass().getClassLoader() : loader, clazz);
@@ -4473,8 +4476,8 @@
* @param clazz The type of the serializable expected or {@code null} for performing no checks
*/
@Nullable
- private <T> T readSerializableInternal(@Nullable final ClassLoader loader,
- @Nullable Class<T> clazz) {
+ private <T extends Serializable> T readSerializableInternal(@Nullable final ClassLoader loader,
+ @Nullable Class<? super T> clazz) {
String name = readString();
if (name == null) {
// For some reason we were unable to read the name of the Serializable (either there
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a63f68a..2fe0622 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -280,6 +280,26 @@
public static final int LAST_APPLICATION_UID = 19999;
/**
+ * Defines the start of a range of UIDs going from this number to
+ * {@link #LAST_SUPPLEMENTAL_UID} that are reserved for assigning to
+ * supplemental processes. There is a 1-1 mapping between a supplemental
+ * process UID and the app that it belongs to, which can be computed by
+ * subtracting (FIRST_SUPPLEMENTAL_UID - FIRST_APPLICATION_UID) from the
+ * uid of a supplemental process.
+ *
+ * Note that there are no GIDs associated with these processes; storage
+ * attribution for them will be done using project IDs.
+ * @hide
+ */
+ public static final int FIRST_SUPPLEMENTAL_UID = 20000;
+
+ /**
+ * Last UID that is used for supplemental processes.
+ * @hide
+ */
+ public static final int LAST_SUPPLEMENTAL_UID = 29999;
+
+ /**
* First uid used for fully isolated sandboxed processes spawned from an app zygote
* @hide
*/
@@ -881,6 +901,46 @@
}
/**
+ * Returns whether the provided UID belongs to a supplemental process.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final boolean isSupplemental(int uid) {
+ uid = UserHandle.getAppId(uid);
+ return (uid >= FIRST_SUPPLEMENTAL_UID && uid <= LAST_SUPPLEMENTAL_UID);
+ }
+
+ /**
+ *
+ * Returns the app process corresponding to a supplemental process.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int toAppUid(int uid) {
+ return uid - (FIRST_SUPPLEMENTAL_UID - FIRST_APPLICATION_UID);
+ }
+
+ /**
+ *
+ * Returns the supplemental process corresponding to an app process.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int toSupplementalUid(int uid) {
+ return uid + (FIRST_SUPPLEMENTAL_UID - FIRST_APPLICATION_UID);
+ }
+
+ /**
+ * Returns whether the current process is a supplemental process.
+ */
+ public static final boolean isSupplemental() {
+ return isSupplemental(myUid());
+ }
+
+ /**
* Returns the UID assigned to a particular user name, or -1 if there is
* none. If the given string consists of only numbers, it is converted
* directly to a uid.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 29accb9..8df659d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -80,6 +80,7 @@
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -1443,28 +1444,39 @@
*
* @hide
*/
- public static final int STORAGE_THRESHOLD_PERCENT_HIGH = 20;
+ public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH = 20;
+ /** {@hide} */
+ @TestApi
+ public static final String
+ STORAGE_THRESHOLD_PERCENT_HIGH_KEY = "storage_threshold_percent_high";
/**
* Devices having below STORAGE_THRESHOLD_PERCENT_LOW of total space free are considered to be
- * in low free space category.
+ * in low free space category and can be configured via
+ * Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE.
*
* @hide
*/
- public static final int STORAGE_THRESHOLD_PERCENT_LOW = 5;
+ public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW = 5;
/**
* For devices in high free space category, CACHE_RESERVE_PERCENT_HIGH percent of total space is
* allocated for cache.
*
* @hide
*/
- public static final int CACHE_RESERVE_PERCENT_HIGH = 10;
+ public static final int DEFAULT_CACHE_RESERVE_PERCENT_HIGH = 10;
+ /** {@hide} */
+ @TestApi
+ public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
/**
* For devices in low free space category, CACHE_RESERVE_PERCENT_LOW percent of total space is
* allocated for cache.
*
* @hide
*/
- public static final int CACHE_RESERVE_PERCENT_LOW = 2;
+ public static final int DEFAULT_CACHE_RESERVE_PERCENT_LOW = 2;
+ /** {@hide} */
+ @TestApi
+ public static final String CACHE_RESERVE_PERCENT_LOW_KEY = "cache_reserve_percent_low";
private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
@@ -1490,7 +1502,8 @@
@UnsupportedAppUsage
public long getStorageLowBytes(File path) {
final long lowPercent = Settings.Global.getInt(mResolver,
- Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, STORAGE_THRESHOLD_PERCENT_LOW);
+ Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+ DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW);
final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
final long maxLowBytes = Settings.Global.getLong(mResolver,
@@ -1510,24 +1523,33 @@
@TestApi
@SuppressLint("StreamFiles")
public long computeStorageCacheBytes(@NonNull File path) {
+ final int storageThresholdPercentHigh = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ STORAGE_THRESHOLD_PERCENT_HIGH_KEY, DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH);
+ final int cacheReservePercentHigh = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ CACHE_RESERVE_PERCENT_HIGH_KEY, DEFAULT_CACHE_RESERVE_PERCENT_HIGH);
+ final int cacheReservePercentLow = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ CACHE_RESERVE_PERCENT_LOW_KEY, DEFAULT_CACHE_RESERVE_PERCENT_LOW);
final long totalBytes = path.getTotalSpace();
final long usableBytes = path.getUsableSpace();
- final long storageThresholdHighBytes = totalBytes * STORAGE_THRESHOLD_PERCENT_HIGH / 100;
+ final long storageThresholdHighBytes = totalBytes * storageThresholdPercentHigh / 100;
final long storageThresholdLowBytes = getStorageLowBytes(path);
long result;
if (usableBytes > storageThresholdHighBytes) {
- // If free space is >STORAGE_THRESHOLD_PERCENT_HIGH of total space,
- // reserve CACHE_RESERVE_PERCENT_HIGH of total space
- result = totalBytes * CACHE_RESERVE_PERCENT_HIGH / 100;
+ // If free space is >storageThresholdPercentHigh of total space,
+ // reserve cacheReservePercentHigh of total space
+ result = totalBytes * cacheReservePercentHigh / 100;
} else if (usableBytes < storageThresholdLowBytes) {
- // If free space is <min(STORAGE_THRESHOLD_PERCENT_LOW of total space, 500MB),
- // reserve CACHE_RESERVE_PERCENT_LOW of total space
- result = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100;
+ // If free space is <min(storageThresholdPercentLow of total space, 500MB),
+ // reserve cacheReservePercentLow of total space
+ result = totalBytes * cacheReservePercentLow / 100;
} else {
// Else, linearly interpolate the amount of space to reserve
- double slope = (CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW) * totalBytes
+ double slope = (cacheReservePercentHigh - cacheReservePercentLow) * totalBytes
/ (100.0 * (storageThresholdHighBytes - storageThresholdLowBytes));
- double intercept = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100.0
+ double intercept = totalBytes * cacheReservePercentLow / 100.0
- storageThresholdLowBytes * slope;
result = Math.round(slope * usableBytes + intercept);
}
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 5814bac..0894e37 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -56,6 +56,6 @@
in AndroidFuture<String> callback);
void getUnusedAppCount(
in AndroidFuture callback);
- void selfRevokePermissions(in String packageName, in List<String> permissions,
+ void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 8e5581b..1c0320e 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,7 +76,7 @@
List<SplitPermissionInfoParcelable> getSplitPermissions();
- void selfRevokePermissions(String packageName, in List<String> permissions);
+ void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
void startOneTimePermissionSession(String packageName, int userId, long timeout,
int importanceToResetTimer, int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 47cd107..8733ac4 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -836,15 +836,15 @@
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
- * @see Context#selfRevokePermissions(Collection)
+ * @see Context#revokeOwnPermissionsOnKill(Collection)
*
* @hide
*/
- public void selfRevokePermissions(@NonNull String packageName,
+ public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> future = new AndroidFuture<>();
- service.selfRevokePermissions(packageName, permissions, future);
+ service.revokeOwnPermissionsOnKill(packageName, permissions, future);
return future;
}).whenComplete((result, err) -> {
if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index dcbab62..b1e3cfc 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -337,10 +337,10 @@
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
- * @see PermissionManager#selfRevokePermissions(java.util.Collection)
+ * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
*/
@BinderThread
- public void onSelfRevokePermissions(@NonNull String packageName,
+ public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -669,13 +669,13 @@
}
@Override
- public void selfRevokePermissions(@NonNull String packageName,
+ public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
enforceSomePermissionsGrantedToCaller(
Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
- onSelfRevokePermissions(packageName, permissions,
+ onRevokeOwnPermissionsOnKill(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 13941dc..e4aee76 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -562,12 +562,12 @@
}
/**
- * @see Context#selfRevokePermissions(Collection)
+ * @see Context#revokeOwnPermissionsOnKill(Collection)
* @hide
*/
- public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+ public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
try {
- mPermissionManager.selfRevokePermissions(mContext.getPackageName(),
+ mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
new ArrayList<String>(permissions));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e568370..be2e3b2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9063,6 +9063,16 @@
public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
/**
+ * The complications that are enabled to be shown over the screensaver by the user. Holds
+ * a comma separated list of
+ * {@link com.android.settingslib.dream.DreamBackend.ComplicationType}.
+ *
+ * @hide
+ */
+ public static final String SCREENSAVER_ENABLED_COMPLICATIONS =
+ "screensaver_enabled_complications";
+
+ /**
* The default NFC payment component
* @hide
*/
@@ -12823,16 +12833,6 @@
SYS_STORAGE_CACHE_PERCENTAGE = "sys_storage_cache_percentage";
/**
- * Maximum bytes of storage on the device that is reserved for cached
- * data.
- *
- * @hide
- */
- @Readable
- public static final String
- SYS_STORAGE_CACHE_MAX_BYTES = "sys_storage_cache_max_bytes";
-
- /**
* The maximum reconnect delay for short network outages or when the
* network is suspended due to phone use.
*
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 8242f4e..44a8862 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -17,6 +17,7 @@
package android.service.persistentdata;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -25,6 +26,8 @@
import android.os.RemoteException;
import android.service.oemlock.OemLockManager;
+import com.android.internal.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -50,6 +53,7 @@
@SystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE)
public class PersistentDataBlockManager {
private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
+ private final Context mContext;
private IPersistentDataBlockService sService;
/**
@@ -74,7 +78,10 @@
public @interface FlashLockState {}
/** @hide */
- public PersistentDataBlockManager(IPersistentDataBlockService service) {
+ public PersistentDataBlockManager(
+ Context context,
+ IPersistentDataBlockService service) {
+ mContext = context;
sService = service;
}
@@ -204,4 +211,15 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns the package name which can access the persistent data partition.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public String getPersistentDataPackageName() {
+ return mContext.getString(R.string.config_persistentDataPackageName);
+ }
}
diff --git a/core/java/android/service/security/attestationverification/OWNERS b/core/java/android/service/security/attestationverification/OWNERS
new file mode 100644
index 0000000..12c9978
--- /dev/null
+++ b/core/java/android/service/security/attestationverification/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/core/java/android/security/attestationverification/OWNERS
diff --git a/core/java/android/service/smartspace/SmartspaceService.java b/core/java/android/service/smartspace/SmartspaceService.java
index 7dd85cc..b903fbe 100644
--- a/core/java/android/service/smartspace/SmartspaceService.java
+++ b/core/java/android/service/smartspace/SmartspaceService.java
@@ -245,7 +245,9 @@
public abstract void onDestroySmartspaceSession(@NonNull SmartspaceSessionId sessionId);
private void doDestroy(@NonNull SmartspaceSessionId sessionId) {
- Log.d(TAG, "doDestroy mSessionCallbacks: " + mSessionCallbacks);
+ if (DEBUG) {
+ Log.d(TAG, "doDestroy mSessionCallbacks: " + mSessionCallbacks);
+ }
super.onDestroy();
mSessionCallbacks.remove(sessionId);
onDestroySmartspaceSession(sessionId);
diff --git a/core/java/android/window/BackNavigationInfo.aidl b/core/java/android/window/BackNavigationInfo.aidl
new file mode 100644
index 0000000..1529902
--- /dev/null
+++ b/core/java/android/window/BackNavigationInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.window;
+
+/**
+ * @hide
+ */
+parcelable BackNavigationInfo;
\ No newline at end of file
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
new file mode 100644
index 0000000..571714c
--- /dev/null
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2021 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.window;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.hardware.HardwareBuffer;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteCallback;
+import android.view.SurfaceControl;
+
+/**
+ * Information to be sent to SysUI about a back event.
+ *
+ * @hide
+ */
+public final class BackNavigationInfo implements Parcelable {
+
+ /**
+ * The target of the back navigation is undefined.
+ */
+ public static final int TYPE_UNDEFINED = -1;
+
+ /**
+ * Navigating back will close the currently visible dialog
+ */
+ public static final int TYPE_DIALOG_CLOSE = 0;
+
+ /**
+ * Navigating back will bring the user back to the home screen
+ */
+ public static final int TYPE_RETURN_TO_HOME = 1;
+
+ /**
+ * Navigating back will bring the user to the previous activity in the same Task
+ */
+ public static final int TYPE_CROSS_ACTIVITY = 2;
+
+ /**
+ * Navigating back will bring the user to the previous activity in the previous Task
+ */
+ public static final int TYPE_CROSS_TASK = 3;
+
+ /**
+ * Defines the type of back destinations a back even can lead to. This is used to define the
+ * type of animation that need to be run on SystemUI.
+ */
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_UNDEFINED,
+ TYPE_DIALOG_CLOSE,
+ TYPE_RETURN_TO_HOME,
+ TYPE_CROSS_ACTIVITY,
+ TYPE_CROSS_TASK})
+ @interface BackTargetType {
+ }
+
+ private final int mType;
+ @Nullable
+ private final SurfaceControl mDepartingWindowContainer;
+ @Nullable
+ private final SurfaceControl mScreenshotSurface;
+ @Nullable
+ private final HardwareBuffer mScreenshotBuffer;
+ @Nullable
+ private final RemoteCallback mRemoteCallback;
+ @Nullable
+ private final WindowConfiguration mTaskWindowConfiguration;
+
+ /**
+ * Create a new {@link BackNavigationInfo} instance.
+ *
+ * @param type The {@link BackTargetType} of the destination (what will be displayed after
+ * the back action)
+ * @param topWindowLeash The leash to animate away the current topWindow. The consumer
+ * of the leash is responsible for removing it.
+ * @param screenshotSurface The screenshot of the previous activity to be displayed.
+ * @param screenshotBuffer A buffer containing a screenshot used to display the activity.
+ * See {@link #getScreenshotHardwareBuffer()} for information
+ * about nullity.
+ * @param taskWindowConfiguration The window configuration of the Task being animated
+ * beneath.
+ * @param onBackNavigationDone The callback to be called once the client is done with the back
+ * preview.
+ */
+ public BackNavigationInfo(@BackTargetType int type,
+ @Nullable SurfaceControl topWindowLeash,
+ @Nullable SurfaceControl screenshotSurface,
+ @Nullable HardwareBuffer screenshotBuffer,
+ @Nullable WindowConfiguration taskWindowConfiguration,
+ @NonNull RemoteCallback onBackNavigationDone) {
+ mType = type;
+ mDepartingWindowContainer = topWindowLeash;
+ mScreenshotSurface = screenshotSurface;
+ mScreenshotBuffer = screenshotBuffer;
+ mTaskWindowConfiguration = taskWindowConfiguration;
+ mRemoteCallback = onBackNavigationDone;
+ }
+
+ private BackNavigationInfo(@NonNull Parcel in) {
+ mType = in.readInt();
+ mDepartingWindowContainer = in.readTypedObject(SurfaceControl.CREATOR);
+ mScreenshotSurface = in.readTypedObject(SurfaceControl.CREATOR);
+ mScreenshotBuffer = in.readTypedObject(HardwareBuffer.CREATOR);
+ mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
+ mRemoteCallback = requireNonNull(in.readTypedObject(RemoteCallback.CREATOR));
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeTypedObject(mDepartingWindowContainer, flags);
+ dest.writeTypedObject(mScreenshotSurface, flags);
+ dest.writeTypedObject(mScreenshotBuffer, flags);
+ dest.writeTypedObject(mTaskWindowConfiguration, flags);
+ dest.writeTypedObject(mRemoteCallback, flags);
+ }
+
+ /**
+ * Returns the type of back navigation that is about to happen.
+ * @see BackTargetType
+ */
+ public @BackTargetType int getType() {
+ return mType;
+ }
+
+ /**
+ * Returns a leash to the top window container that needs to be animated. This can be null if
+ * the back animation is controlled by the application.
+ */
+ @Nullable
+ public SurfaceControl getDepartingWindowContainer() {
+ return mDepartingWindowContainer;
+ }
+
+ /**
+ * Returns the {@link SurfaceControl} that should be used to display a screenshot of the
+ * previous activity.
+ */
+ @Nullable
+ public SurfaceControl getScreenshotSurface() {
+ return mScreenshotSurface;
+ }
+
+ /**
+ * Returns the {@link HardwareBuffer} containing the screenshot the activity about to be
+ * shown. This can be null if one of the following conditions is met:
+ * <ul>
+ * <li>The screenshot is not available
+ * <li> The previous activity is the home screen ( {@link #TYPE_RETURN_TO_HOME}
+ * <li> The current window is a dialog ({@link #TYPE_DIALOG_CLOSE}
+ * <li> The back animation is controlled by the application
+ * </ul>
+ */
+ @Nullable
+ public HardwareBuffer getScreenshotHardwareBuffer() {
+ return mScreenshotBuffer;
+ }
+
+ /**
+ * Returns the {@link WindowConfiguration} of the current task. This is null when the top
+ * application is controlling the back animation.
+ */
+ @Nullable
+ public WindowConfiguration getTaskWindowConfiguration() {
+ return mTaskWindowConfiguration;
+ }
+
+ /**
+ * Callback to be called when the back preview is finished in order to notify the server that
+ * it can clean up the resources created for the animation.
+ */
+ public void onBackNavigationFinished() {
+ mRemoteCallback.sendResult(null);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<BackNavigationInfo> CREATOR = new Creator<BackNavigationInfo>() {
+ @Override
+ public BackNavigationInfo createFromParcel(Parcel in) {
+ return new BackNavigationInfo(in);
+ }
+
+ @Override
+ public BackNavigationInfo[] newArray(int size) {
+ return new BackNavigationInfo[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "BackNavigationInfo{"
+ + "mType=" + typeToString(mType) + " (" + mType + ")"
+ + ", mDepartingWindowContainer=" + mDepartingWindowContainer
+ + ", mScreenshotSurface=" + mScreenshotSurface
+ + ", mTaskWindowConfiguration= " + mTaskWindowConfiguration
+ + ", mScreenshotBuffer=" + mScreenshotBuffer
+ + ", mRemoteCallback=" + mRemoteCallback
+ + '}';
+ }
+
+ /**
+ * Translates the {@link BackNavigationInfo} integer type to its String representation
+ */
+ public static String typeToString(@BackTargetType int type) {
+ switch (type) {
+ case TYPE_UNDEFINED:
+ return "TYPE_UNDEFINED";
+ case TYPE_DIALOG_CLOSE:
+ return "TYPE_DIALOG_CLOSE";
+ case TYPE_RETURN_TO_HOME:
+ return "TYPE_RETURN_TO_HOME";
+ case TYPE_CROSS_ACTIVITY:
+ return "TYPE_CROSS_ACTIVITY";
+ case TYPE_CROSS_TASK:
+ return "TYPE_CROSS_TASK";
+ }
+ return String.valueOf(type);
+ }
+}
diff --git a/core/java/com/android/internal/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java
index 62517fa..bf23ad1 100644
--- a/core/java/com/android/internal/midi/MidiFramer.java
+++ b/core/java/com/android/internal/midi/MidiFramer.java
@@ -99,6 +99,12 @@
}
} else { // data byte
if (!mInSysEx) {
+ // Hack to avoid crashing if we start parsing in the middle
+ // of a data stream
+ if (mNeeded <= 0) {
+ break;
+ }
+
mBuffer[mCount++] = currentByte;
if (--mNeeded == 0) {
if (mRunningStatus != 0) {
diff --git a/core/java/com/android/internal/midi/OWNERS b/core/java/com/android/internal/midi/OWNERS
new file mode 100644
index 0000000..af273a6
--- /dev/null
+++ b/core/java/com/android/internal/midi/OWNERS
@@ -0,0 +1 @@
+include /services/midi/OWNERS
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 451eec0..7c203fb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12758,6 +12758,8 @@
SparseLongArray rxPackets = new SparseLongArray();
SparseLongArray txPackets = new SparseLongArray();
+ SparseLongArray rxTimesMs = new SparseLongArray();
+ SparseLongArray txTimesMs = new SparseLongArray();
long totalTxPackets = 0;
long totalRxPackets = 0;
if (delta != null) {
@@ -12791,7 +12793,7 @@
mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
entry.rxPackets);
- add(rxPackets, uid, entry.rxPackets);
+ rxPackets.incrementValue(uid, entry.rxPackets);
// Sum the total number of packets so that the Rx Power can
// be evenly distributed amongst the apps.
@@ -12810,7 +12812,7 @@
mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
entry.txPackets);
- add(txPackets, uid, entry.txPackets);
+ txPackets.incrementValue(uid, entry.txPackets);
// Sum the total number of packets so that the Tx Power can
// be evenly distributed amongst the apps.
@@ -12934,12 +12936,9 @@
+ scanTxTimeSinceMarkMs + " ms)");
}
- ControllerActivityCounterImpl activityCounter =
- uid.getOrCreateWifiControllerActivityLocked();
- activityCounter.getOrCreateRxTimeCounter()
- .increment(scanRxTimeSinceMarkMs, elapsedRealtimeMs);
- activityCounter.getOrCreateTxTimeCounters()[0]
- .increment(scanTxTimeSinceMarkMs, elapsedRealtimeMs);
+ rxTimesMs.incrementValue(uid.getUid(), scanRxTimeSinceMarkMs);
+ txTimesMs.incrementValue(uid.getUid(), scanTxTimeSinceMarkMs);
+
leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
}
@@ -12978,36 +12977,51 @@
// Distribute the remaining Tx power appropriately between all apps that transmitted
// packets.
for (int i = 0; i < txPackets.size(); i++) {
- final Uid uid = getUidStatsLocked(txPackets.keyAt(i),
- elapsedRealtimeMs, uptimeMs);
+ final int uid = txPackets.keyAt(i);
final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs)
/ totalTxPackets;
- if (DEBUG_ENERGY) {
- Slog.d(TAG, " TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
- }
- uid.getOrCreateWifiControllerActivityLocked().getOrCreateTxTimeCounters()[0]
- .increment(myTxTimeMs, elapsedRealtimeMs);
- if (uidEstimatedConsumptionMah != null) {
- uidEstimatedConsumptionMah.incrementValue(uid.getUid(),
- mWifiPowerCalculator.calcPowerFromControllerDataMah(
- 0, myTxTimeMs, 0));
- }
+ txTimesMs.incrementValue(uid, myTxTimeMs);
}
// Distribute the remaining Rx power appropriately between all apps that received
// packets.
for (int i = 0; i < rxPackets.size(); i++) {
- final Uid uid = getUidStatsLocked(rxPackets.keyAt(i),
- elapsedRealtimeMs, uptimeMs);
+ final int uid = rxPackets.keyAt(i);
final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs)
/ totalRxPackets;
+ rxTimesMs.incrementValue(uid, myRxTimeMs);
+ }
+
+ for (int i = 0; i < txTimesMs.size(); i++) {
+ final int uid = txTimesMs.keyAt(i);
+ final long myTxTimeMs = txTimesMs.valueAt(i);
if (DEBUG_ENERGY) {
- Slog.d(TAG, " RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
+ Slog.d(TAG, " TxTime for UID " + uid + ": " + myTxTimeMs + " ms");
}
- uid.getOrCreateWifiControllerActivityLocked().getOrCreateRxTimeCounter()
+ getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+ .getOrCreateWifiControllerActivityLocked()
+ .getOrCreateTxTimeCounters()[0]
+ .increment(myTxTimeMs, elapsedRealtimeMs);
+ if (uidEstimatedConsumptionMah != null) {
+ uidEstimatedConsumptionMah.incrementValue(uid,
+ mWifiPowerCalculator.calcPowerFromControllerDataMah(
+ 0, myTxTimeMs, 0));
+ }
+ }
+
+ for (int i = 0; i < rxTimesMs.size(); i++) {
+ final int uid = rxTimesMs.keyAt(i);
+ final long myRxTimeMs = rxTimesMs.valueAt(i);
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, " RxTime for UID " + uid + ": " + myRxTimeMs + " ms");
+ }
+
+ getUidStatsLocked(rxTimesMs.keyAt(i), elapsedRealtimeMs, uptimeMs)
+ .getOrCreateWifiControllerActivityLocked()
+ .getOrCreateRxTimeCounter()
.increment(myRxTimeMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
- uidEstimatedConsumptionMah.incrementValue(uid.getUid(),
+ uidEstimatedConsumptionMah.incrementValue(uid,
mWifiPowerCalculator.calcPowerFromControllerDataMah(
myRxTimeMs, 0, 0));
}
@@ -13015,7 +13029,6 @@
// Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
-
// Update WiFi controller stats.
mWifiActivity.getOrCreateRxTimeCounter().increment(
info.getControllerRxDurationMillis(), elapsedRealtimeMs);
@@ -13353,8 +13366,8 @@
energy = info.getControllerEnergyUsed();
if (!info.getUidTraffic().isEmpty()) {
for (UidTraffic traffic : info.getUidTraffic()) {
- add(uidRxBytes, traffic.getUid(), traffic.getRxBytes());
- add(uidTxBytes, traffic.getUid(), traffic.getTxBytes());
+ uidRxBytes.incrementValue(traffic.getUid(), traffic.getRxBytes());
+ uidTxBytes.incrementValue(traffic.getUid(), traffic.getTxBytes());
}
}
}
@@ -13446,6 +13459,9 @@
long leftOverRxTimeMs = rxTimeMs;
long leftOverTxTimeMs = txTimeMs;
+ final SparseLongArray rxTimesMs = new SparseLongArray(uidCount);
+ final SparseLongArray txTimesMs = new SparseLongArray(uidCount);
+
for (int i = 0; i < uidCount; i++) {
final Uid u = mUidStats.valueAt(i);
if (u.mBluetoothScanTimer == null) {
@@ -13475,12 +13491,8 @@
scanTimeTxSinceMarkMs = (txTimeMs * scanTimeTxSinceMarkMs) / totalScanTimeMs;
}
- final ControllerActivityCounterImpl counter =
- u.getOrCreateBluetoothControllerActivityLocked();
- counter.getOrCreateRxTimeCounter()
- .increment(scanTimeRxSinceMarkMs, elapsedRealtimeMs);
- counter.getOrCreateTxTimeCounters()[0]
- .increment(scanTimeTxSinceMarkMs, elapsedRealtimeMs);
+ rxTimesMs.incrementValue(u.getUid(), scanTimeRxSinceMarkMs);
+ txTimesMs.incrementValue(u.getUid(), scanTimeTxSinceMarkMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.incrementValue(u.getUid(),
@@ -13544,29 +13556,45 @@
if (totalRxBytes > 0 && rxBytes > 0) {
final long timeRxMs = (leftOverRxTimeMs * rxBytes) / totalRxBytes;
- if (DEBUG_ENERGY) {
- Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
- }
- counter.getOrCreateRxTimeCounter().increment(timeRxMs, elapsedRealtimeMs);
-
- if (uidEstimatedConsumptionMah != null) {
- uidEstimatedConsumptionMah.incrementValue(u.getUid(),
- mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0));
- }
+ rxTimesMs.incrementValue(uid, timeRxMs);
}
if (totalTxBytes > 0 && txBytes > 0) {
final long timeTxMs = (leftOverTxTimeMs * txBytes) / totalTxBytes;
- if (DEBUG_ENERGY) {
- Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
- }
- counter.getOrCreateTxTimeCounters()[0]
- .increment(timeTxMs, elapsedRealtimeMs);
+ txTimesMs.incrementValue(uid, timeTxMs);
+ }
+ }
- if (uidEstimatedConsumptionMah != null) {
- uidEstimatedConsumptionMah.incrementValue(u.getUid(),
- mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0));
- }
+ for (int i = 0; i < txTimesMs.size(); i++) {
+ final int uid = txTimesMs.keyAt(i);
+ final long myTxTimeMs = txTimesMs.valueAt(i);
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, " TxTime for UID " + uid + ": " + myTxTimeMs + " ms");
+ }
+ getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+ .getOrCreateBluetoothControllerActivityLocked()
+ .getOrCreateTxTimeCounters()[0]
+ .increment(myTxTimeMs, elapsedRealtimeMs);
+ if (uidEstimatedConsumptionMah != null) {
+ uidEstimatedConsumptionMah.incrementValue(uid,
+ mBluetoothPowerCalculator.calculatePowerMah(0, myTxTimeMs, 0));
+ }
+ }
+
+ for (int i = 0; i < rxTimesMs.size(); i++) {
+ final int uid = rxTimesMs.keyAt(i);
+ final long myRxTimeMs = rxTimesMs.valueAt(i);
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, " RxTime for UID " + uid + ": " + myRxTimeMs + " ms");
+ }
+
+ getUidStatsLocked(rxTimesMs.keyAt(i), elapsedRealtimeMs, uptimeMs)
+ .getOrCreateBluetoothControllerActivityLocked()
+ .getOrCreateRxTimeCounter()
+ .increment(myRxTimeMs, elapsedRealtimeMs);
+ if (uidEstimatedConsumptionMah != null) {
+ uidEstimatedConsumptionMah.incrementValue(uid,
+ mBluetoothPowerCalculator.calculatePowerMah(myRxTimeMs, 0, 0));
}
}
}
@@ -18156,8 +18184,4 @@
pw.println();
dumpMeasuredEnergyStatsLocked(pw);
}
-
- private static void add(SparseLongArray array, int key, long delta) {
- array.put(key, array.get(key) + delta);
- }
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 5ac4936..def598c 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -85,6 +85,8 @@
WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM),
WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+ WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ "CoreBackPreview"),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c367e04..9ed1137 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6105,11 +6105,21 @@
<permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows an application to query over global data in AppSearch.
+ <!-- @SystemApi Allows an application to query over global data in AppSearch.
@hide -->
<permission android:name="android.permission.READ_GLOBAL_APP_SEARCH_DATA"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to query over global data in AppSearch that's visible to the
+ ASSISTANT role. -->
+ <permission android:name="android.permission.READ_ASSISTANT_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to query over global data in AppSearch that's visible to the
+ HOME role. -->
+ <permission android:name="android.permission.READ_HOME_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
<!-- @SystemApi Allows an application to create virtual devices in VirtualDeviceManager.
@hide -->
<permission android:name="android.permission.CREATE_VIRTUAL_DEVICE"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e232d85..6a7b4af 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9376,11 +9376,12 @@
<attr name="canPauseRecording" format="boolean" />
</declare-styleable>
- <!-- Use <code>tv-iapp</code> as the root tag of the XML resource that describes a
- {@link android.media.tv.interactive.TvIAppService}, which is referenced from its
- {@link android.media.tv.interactive.TvIAppService#SERVICE_META_DATA} meta-data entry.
- Described here are the attributes that can be included in that tag. -->
- <declare-styleable name="TvIAppService">
+ <!-- Use <code>tv-interactive-app</code> as the root tag of the XML resource that describes a
+ {@link android.media.tv.interactive.TvInteractiveAppService}, which is referenced
+ from its
+ {@link android.media.tv.interactive.TvInteractiveAppService#SERVICE_META_DATA}
+ meta-data entry. Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="TvInteractiveAppService">
<!-- The interactive app types that the TV interactive app service supports.
Reference to a string array resource that describes the supported types,
e.g. HbbTv, Ginga. -->
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index d0a13fc..ed035e5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -26,6 +26,7 @@
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
+import android.os.WorkSource;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -52,6 +53,12 @@
@Test
public void testTimerBasedModel() {
+ BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ final WorkSource ws = new WorkSource(APP_UID);
+ batteryStats.noteBluetoothScanStartedFromSourceLocked(ws, false, 0, 0);
+ batteryStats.noteBluetoothScanStoppedFromSourceLocked(ws, false, 1000, 1000);
+
setupBluetoothEnergyInfo(0, BatteryStats.POWER_DATA_UNAVAILABLE);
BluetoothPowerCalculator calculator =
@@ -59,8 +66,18 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
- assertCalculatedPower(0.08216, 0.18169, 0.26388, 0.26386,
- BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
+ 0.06944, 3000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(APP_UID),
+ 0.19444, 9000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getDeviceBatteryConsumer(),
+ 0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getAppsBatteryConsumer(),
+ 0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
@Test
@@ -136,8 +153,18 @@
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().includePowerModels().build(),
calculator);
- assertCalculatedPower(0.08216, 0.18169, 0.30030, 0.26386,
- BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
+ 0.08216, 3583, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(APP_UID),
+ 0.18169, 8416, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getDeviceBatteryConsumer(),
+ 0.30030, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getAppsBatteryConsumer(),
+ 0.26386, 11999, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
@Test
@@ -150,8 +177,18 @@
mStatsRule.apply(calculator);
- assertCalculatedPower(0.10378, 0.22950, 0.33333, 0.33329,
- BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
+ 0.10378, 3583, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(APP_UID),
+ 0.22950, 8416, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getDeviceBatteryConsumer(),
+ 0.33333, 12000, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getAppsBatteryConsumer(),
+ 0.33329, 11999, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
}
@Test
@@ -228,8 +265,18 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
- assertCalculatedPower(0.08216, 0.18169, 0.26388, 0.26386,
- BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
+ 0.08216, 3583, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getUidBatteryConsumer(APP_UID),
+ 0.18169, 8416, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getDeviceBatteryConsumer(),
+ 0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ assertBluetoothPowerAndDuration(
+ mStatsRule.getAppsBatteryConsumer(),
+ 0.26386, 11999, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
private void setupBluetoothEnergyInfo(long reportedEnergyUc, long consumedEnergyUc) {
@@ -243,22 +290,6 @@
consumedEnergyUc, 1000, 1000);
}
- private void assertCalculatedPower(double bluetoothUidPowerMah, double appPowerMah,
- double devicePowerMah, double allAppsPowerMah, int powerModelPowerProfile) {
- assertBluetoothPowerAndDuration(
- mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
- bluetoothUidPowerMah, 3583, powerModelPowerProfile);
- assertBluetoothPowerAndDuration(
- mStatsRule.getUidBatteryConsumer(APP_UID),
- appPowerMah, 8416, powerModelPowerProfile);
- assertBluetoothPowerAndDuration(
- mStatsRule.getDeviceBatteryConsumer(),
- devicePowerMah, 12000, powerModelPowerProfile);
- assertBluetoothPowerAndDuration(
- mStatsRule.getAppsBatteryConsumer(),
- allAppsPowerMah, 11999, powerModelPowerProfile);
- }
-
private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
double powerMah, int durationMs, @BatteryConsumer.PowerModel int powerModel) {
assertThat(batteryConsumer).isNotNull();
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index a787357..a368399 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -92,7 +92,10 @@
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
- batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 1000, 1000,
+ batteryStats.noteWifiScanStartedLocked(APP_UID, 500, 500);
+ batteryStats.noteWifiScanStoppedLocked(APP_UID, 1500, 1500);
+
+ batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 2000, 2000,
mNetworkStatsManager);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
@@ -100,15 +103,15 @@
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
- .isEqualTo(1423);
+ .isEqualTo(2473);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
- .isWithin(PRECISION).of(0.2214666);
+ .isWithin(PRECISION).of(0.3964);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
- .isEqualTo(4002);
+ .isEqualTo(4001);
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.86666);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 6f5951b..1068c27 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -394,6 +394,9 @@
<permission name="android.permission.SET_WALLPAPER_COMPONENT" />
<permission name="android.permission.SET_WALLPAPER_DIM_AMOUNT" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+ <!-- Permission required for CTS test - TrustTestCases -->
+ <permission name="android.permission.PROVIDE_TRUST_AGENT" />
+ <permission name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<!-- Permissions required for Incremental CTS tests -->
<permission name="com.android.permission.USE_INSTALLER_V2"/>
<permission name="android.permission.LOADER_USAGE_STATS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 535d656..9b67cfc 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -103,18 +103,6 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
- "-2002500255": {
- "message": "Defer removing snapshot surface in %dms",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
- },
- "-1991255017": {
- "message": "Drawing snapshot surface sizeMismatch=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
- },
"-1980468143": {
"message": "DisplayArea appeared name=%s",
"level": "VERBOSE",
@@ -745,6 +733,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1343787701": {
+ "message": "startBackNavigation task=%s, topRunningActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"-1340540100": {
"message": "Creating SnapshotStartingData",
"level": "VERBOSE",
@@ -1597,12 +1591,6 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "-405536909": {
- "message": "Removing snapshot surface",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
- },
"-401282500": {
"message": "destroyIfPossible: r=%s destroy returned removed=%s",
"level": "DEBUG",
@@ -1867,6 +1855,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/Task.java"
},
+ "-134091882": {
+ "message": "Screenshotting Activity %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/TaskFragment.java"
+ },
"-124316973": {
"message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
"level": "VERBOSE",
@@ -1951,6 +1945,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/WindowContainer.java"
},
+ "-23020844": {
+ "message": "Back: Reset surfaces",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"-21399771": {
"message": "activity %s already destroying, skipping request with reason:%s",
"level": "VERBOSE",
@@ -2005,12 +2005,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "44438983": {
- "message": "performLayout: Activity exiting now removed %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"45285419": {
"message": "startingWindow was set but startingSurface==null, couldn't remove",
"level": "VERBOSE",
@@ -3271,12 +3265,6 @@
"group": "WM_DEBUG_LAYER_MIRRORING",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "1417601133": {
- "message": "Enqueueing ADD_STARTING",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"1422781269": {
"message": "Resuming rotation after re-position",
"level": "DEBUG",
@@ -3397,6 +3385,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1554795024": {
+ "message": "Previous Activity is %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"1557732761": {
"message": "For Intent %s bringing to top: %s",
"level": "DEBUG",
@@ -3924,6 +3918,9 @@
"WM_DEBUG_APP_TRANSITIONS_ANIM": {
"tag": "WindowManager"
},
+ "WM_DEBUG_BACK_PREVIEW": {
+ "tag": "CoreBackPreview"
+ },
"WM_DEBUG_BOOT": {
"tag": "WindowManager"
},
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
new file mode 100644
index 0000000..b310dd6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.back;
+
+import android.view.MotionEvent;
+
+/**
+ * Interface for SysUI to get access to the Back animation related methods.
+ */
+public interface BackAnimation {
+
+ /**
+ * Called when a {@link MotionEvent} is generated by a back gesture.
+ */
+ void onBackMotion(MotionEvent event);
+
+ /**
+ * Sets whether the back gesture is past the trigger threshold or not.
+ */
+ void setTriggerBack(boolean triggerBack);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
new file mode 100644
index 0000000..229e8ee0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.back;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.WindowConfiguration;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.hardware.HardwareBuffer;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.window.BackNavigationInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
+/**
+ * Controls the window animation run when a user initiates a back gesture.
+ */
+public class BackAnimationController {
+
+ private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+ public static final boolean IS_ENABLED = SystemProperties
+ .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ private static final String TAG = "BackAnimationController";
+
+ /**
+ * Location of the initial touch event of the back gesture.
+ */
+ private final PointF mInitTouchLocation = new PointF();
+
+ /**
+ * Raw delta between {@link #mInitTouchLocation} and the last touch location.
+ */
+ private final Point mTouchEventDelta = new Point();
+ private final ShellExecutor mShellExecutor;
+
+ /** True when a back gesture is ongoing */
+ private boolean mBackGestureStarted = false;
+
+ /** @see #setTriggerBack(boolean) */
+ private boolean mTriggerBack;
+
+ @Nullable
+ private BackNavigationInfo mBackNavigationInfo;
+ private final SurfaceControl.Transaction mTransaction;
+ private final IActivityTaskManager mActivityTaskManager;
+
+ public BackAnimationController(@ShellMainThread ShellExecutor shellExecutor) {
+ this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService());
+ }
+
+ @VisibleForTesting
+ BackAnimationController(@NonNull ShellExecutor shellExecutor,
+ @NonNull SurfaceControl.Transaction transaction,
+ @NonNull IActivityTaskManager activityTaskManager) {
+ mShellExecutor = shellExecutor;
+ mTransaction = transaction;
+ mActivityTaskManager = activityTaskManager;
+ }
+
+ public BackAnimation getBackAnimationImpl() {
+ return mBackAnimation;
+ }
+
+ private final BackAnimation mBackAnimation = new BackAnimationImpl();
+
+ private class BackAnimationImpl implements BackAnimation {
+
+ @Override
+ public void onBackMotion(MotionEvent event) {
+ mShellExecutor.execute(() -> onMotionEvent(event));
+ }
+
+ @Override
+ public void setTriggerBack(boolean triggerBack) {
+ mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
+ }
+ }
+
+ /**
+ * Called when a new motion event needs to be transferred to this
+ * {@link BackAnimationController}
+ */
+ public void onMotionEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ initAnimation(event);
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ onMove(event);
+ } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ onGestureFinished();
+ }
+ }
+
+ private void initAnimation(MotionEvent event) {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "initAnimation mMotionStarted=%b", mBackGestureStarted);
+ if (mBackGestureStarted) {
+ Log.e(TAG, "Animation is being initialized but is already started.");
+ return;
+ }
+
+ if (mBackNavigationInfo != null) {
+ finishAnimation();
+ }
+ mInitTouchLocation.set(event.getX(), event.getY());
+ mBackGestureStarted = true;
+
+ try {
+ mBackNavigationInfo = mActivityTaskManager.startBackNavigation();
+ onBackNavigationInfoReceived(mBackNavigationInfo);
+ } catch (RemoteException remoteException) {
+ Log.e(TAG, "Failed to initAnimation", remoteException);
+ finishAnimation();
+ }
+ }
+
+ private void onBackNavigationInfoReceived(@Nullable BackNavigationInfo backNavigationInfo) {
+ if (backNavigationInfo == null
+ || backNavigationInfo.getDepartingWindowContainer() == null) {
+ Log.e(TAG, "Received BackNavigationInfo is null.");
+ finishAnimation();
+ return;
+ }
+
+ HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer();
+ if (hardwareBuffer != null) {
+ displayTargetScreenshot(hardwareBuffer,
+ backNavigationInfo.getTaskWindowConfiguration());
+ }
+ mTransaction.apply();
+ }
+
+ /**
+ * Display the screenshot of the activity beneath.
+ *
+ * @param hardwareBuffer The buffer containing the screenshot.
+ */
+ private void displayTargetScreenshot(@NonNull HardwareBuffer hardwareBuffer,
+ WindowConfiguration taskWindowConfiguration) {
+ SurfaceControl screenshotSurface =
+ mBackNavigationInfo == null ? null : mBackNavigationInfo.getScreenshotSurface();
+ if (screenshotSurface == null) {
+ Log.e(TAG, "BackNavigationInfo doesn't contain a surface for the screenshot. ");
+ return;
+ }
+
+ // Scale the buffer to fill the whole Task
+ float sx = 1;
+ float sy = 1;
+ float w = taskWindowConfiguration.getBounds().width();
+ float h = taskWindowConfiguration.getBounds().height();
+
+ if (w != hardwareBuffer.getWidth()) {
+ sx = w / hardwareBuffer.getWidth();
+ }
+
+ if (h != hardwareBuffer.getHeight()) {
+ sy = h / hardwareBuffer.getHeight();
+ }
+ mTransaction.setScale(screenshotSurface, sx, sy);
+ mTransaction.setBuffer(screenshotSurface, hardwareBuffer);
+ mTransaction.setVisibility(screenshotSurface, true);
+ }
+
+ private void onMove(MotionEvent event) {
+ if (!mBackGestureStarted || mBackNavigationInfo == null) {
+ return;
+ }
+ int deltaX = Math.round(event.getX() - mInitTouchLocation.x);
+ int deltaY = Math.round(event.getY() - mInitTouchLocation.y);
+ ProtoLog.v(WM_SHELL_BACK_PREVIEW, "Runner move: %d %d", deltaX, deltaY);
+ SurfaceControl topWindowLeash = mBackNavigationInfo.getDepartingWindowContainer();
+ mTransaction.setPosition(topWindowLeash, deltaX, deltaY);
+ mTouchEventDelta.set(deltaX, deltaY);
+ mTransaction.apply();
+ }
+
+ private void onGestureFinished() {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "onGestureFinished() mTriggerBack == %s", mTriggerBack);
+ if (mBackGestureStarted) {
+ if (mTriggerBack) {
+ prepareTransition();
+ } else {
+ resetPositionAnimated();
+ }
+ }
+ mBackGestureStarted = false;
+ mTriggerBack = false;
+ }
+
+ /**
+ * Animate the top window leash to its initial position.
+ */
+ private void resetPositionAnimated() {
+ mBackGestureStarted = false;
+ // TODO(208786853) Handle overlap with a new coming gesture.
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Runner: Back not triggered, cancelling animation "
+ + "mLastPos=%s mInitTouch=%s", mTouchEventDelta, mInitTouchLocation);
+
+ // TODO(208427216) : Replace placeholder animation with an actual one.
+ ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f).setDuration(200);
+ animation.addUpdateListener(animation1 -> {
+ if (mBackNavigationInfo == null) {
+ return;
+ }
+ float fraction = animation1.getAnimatedFraction();
+ int deltaX = Math.round(mTouchEventDelta.x - (mTouchEventDelta.x * fraction));
+ int deltaY = Math.round(mTouchEventDelta.y - (mTouchEventDelta.y * fraction));
+ mTransaction.setPosition(mBackNavigationInfo.getDepartingWindowContainer(),
+ deltaX, deltaY);
+ mTransaction.apply();
+ });
+
+ animation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onAnimationEnd");
+ finishAnimation();
+ }
+ });
+ animation.start();
+ }
+
+ private void prepareTransition() {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "prepareTransition()");
+ mTriggerBack = false;
+ mBackGestureStarted = false;
+ }
+
+ /**
+ * Sets to true when the back gesture has passed the triggering threshold, false otherwise.
+ */
+ public void setTriggerBack(boolean triggerBack) {
+ mTriggerBack = triggerBack;
+ }
+
+ private void finishAnimation() {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()");
+ mBackGestureStarted = false;
+ mTouchEventDelta.set(0, 0);
+ mInitTouchLocation.set(0, 0);
+ BackNavigationInfo backNavigationInfo = mBackNavigationInfo;
+ mBackNavigationInfo = null;
+ if (backNavigationInfo == null) {
+ return;
+ }
+ SurfaceControl topWindowLeash = backNavigationInfo.getDepartingWindowContainer();
+ if (topWindowLeash != null && topWindowLeash.isValid()) {
+ mTransaction.remove(topWindowLeash);
+ }
+ SurfaceControl screenshotSurface = backNavigationInfo.getScreenshotSurface();
+ if (screenshotSurface != null && screenshotSurface.isValid()) {
+ mTransaction.remove(screenshotSurface);
+ }
+ mTransaction.apply();
+ backNavigationInfo.onBackNavigationFinished();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackPreviewHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackPreviewHandler.java
deleted file mode 100644
index dc20f7b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackPreviewHandler.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.back;
-
-import android.os.SystemProperties;
-import android.view.IWindowManager;
-
-import javax.inject.Inject;
-
-/**
- * Handle the preview of what a back gesture will lead to.
- */
-public class BackPreviewHandler {
-
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
-
- public static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
- }
-
- private final IWindowManager mWmService;
-
- @Inject
- public BackPreviewHandler(IWindowManager windowManagerService) {
- mWmService = windowManagerService;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 23d9b8b..f61e624 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -40,6 +40,8 @@
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.apppairs.AppPairsController;
+import com.android.wm.shell.back.BackAnimation;
+import com.android.wm.shell.back.BackAnimationController;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.DisplayController;
@@ -238,6 +240,17 @@
}
//
+ // Back animation
+ //
+
+ @WMSingleton
+ @Provides
+ static Optional<BackAnimation> provideBackAnimation(
+ Optional<BackAnimationController> backAnimationController) {
+ return backAnimationController.map(BackAnimationController::getBackAnimationImpl);
+ }
+
+ //
// Bubbles (optional feature)
//
@@ -678,4 +691,16 @@
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
}
+
+ @WMSingleton
+ @Provides
+ static Optional<BackAnimationController> provideBackAnimationController(
+ @ShellMainThread ShellExecutor shellExecutor
+ ) {
+ if (BackAnimationController.IS_ENABLED) {
+ return Optional.of(
+ new BackAnimationController(shellExecutor));
+ }
+ return Optional.empty();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 79c1df2..20c4e21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -34,6 +34,8 @@
Consts.TAG_WM_SHELL),
WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_STARTING_WINDOW),
+ WM_SHELL_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ "ShellBackPreview"),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
new file mode 100644
index 0000000..8446b37
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
@@ -0,0 +1,2 @@
+# window manager > wm shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OWNERS
new file mode 100644
index 0000000..566acc8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OWNERS
@@ -0,0 +1,2 @@
+# window manager > wm shell > Bubbles
+# Bug component: 555586
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
new file mode 100644
index 0000000..8446b37
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
@@ -0,0 +1,2 @@
+# window manager > wm shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/OWNERS
new file mode 100644
index 0000000..172e24bf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/OWNERS
@@ -0,0 +1,2 @@
+# window manager > wm shell > Picture-In-Picture
+# Bug component: 316251
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
new file mode 100644
index 0000000..960c7ac
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.back;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.IActivityTaskManager;
+import android.app.WindowConfiguration;
+import android.hardware.HardwareBuffer;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.window.BackNavigationInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.ShellExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest WMShellUnitTests:BackAnimationControllerTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class BackAnimationControllerTest {
+
+ private final ShellExecutor mShellExecutor = new TestShellExecutor();
+
+ @Mock
+ private SurfaceControl.Transaction mTransaction;
+
+ @Mock
+ private IActivityTaskManager mActivityTaskManager;
+
+ private BackAnimationController mController;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mController = new BackAnimationController(
+ mShellExecutor, mTransaction, mActivityTaskManager);
+ }
+
+ private void createNavigationInfo(SurfaceControl topWindowLeash,
+ SurfaceControl screenshotSurface,
+ HardwareBuffer hardwareBuffer) {
+ BackNavigationInfo navigationInfo = new BackNavigationInfo(
+ BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ topWindowLeash,
+ screenshotSurface,
+ hardwareBuffer,
+ new WindowConfiguration(),
+ new RemoteCallback((bundle) -> {}));
+ try {
+ doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation();
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ @Test
+ public void screenshotAttachedAndVisible() {
+ SurfaceControl topWindowLeash = new SurfaceControl();
+ SurfaceControl screenshotSurface = new SurfaceControl();
+ HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
+ createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
+ mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+ verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
+ verify(mTransaction).setVisibility(screenshotSurface, true);
+ verify(mTransaction).apply();
+ }
+
+ @Test
+ public void surfaceMovesWithGesture() {
+ SurfaceControl topWindowLeash = new SurfaceControl();
+ SurfaceControl screenshotSurface = new SurfaceControl();
+ HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
+ createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
+ mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+ mController.onMotionEvent(MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0));
+ verify(mTransaction).setPosition(topWindowLeash, 100, 100);
+ verify(mTransaction, atLeastOnce()).apply();
+ }
+}
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 1fc2cf9..6168c22 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -18,12 +18,16 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.graphics.GraphicBuffer;
import android.graphics.ImageFormat;
import android.graphics.ImageFormat.Format;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.hardware.DataSpace;
+import android.hardware.DataSpace.NamedDataSpace;
import android.hardware.HardwareBuffer;
+import android.hardware.HardwareBuffer.Usage;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
@@ -95,10 +99,18 @@
private ListenerHandler mListenerHandler;
private long mNativeContext;
+ private int mWidth;
+ private int mHeight;
+ private final int mMaxImages;
+ private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
+ private @HardwareBuffer.Format int mHardwareBufferFormat;
+ private @NamedDataSpace long mDataSpace;
+ private boolean mUseLegacyImageFormat;
+ private boolean mUseSurfaceImageFormatInfo;
+
// Field below is used by native code, do not access or modify.
private int mWriterFormat;
- private final int mMaxImages;
// Keep track of the currently dequeued Image. This need to be thread safe as the images
// could be closed by different threads (e.g., application thread and GC thread).
private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>();
@@ -131,7 +143,7 @@
*/
public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
@IntRange(from = 1) int maxImages) {
- return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN, -1 /*width*/,
+ return new ImageWriter(surface, maxImages, true, ImageFormat.UNKNOWN, -1 /*width*/,
-1 /*height*/);
}
@@ -183,7 +195,7 @@
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
throw new IllegalArgumentException("Invalid format is specified: " + format);
}
- return new ImageWriter(surface, maxImages, format, width, height);
+ return new ImageWriter(surface, maxImages, false, format, width, height);
}
/**
@@ -232,48 +244,49 @@
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
throw new IllegalArgumentException("Invalid format is specified: " + format);
}
- return new ImageWriter(surface, maxImages, format, -1 /*width*/, -1 /*height*/);
+ return new ImageWriter(surface, maxImages, false, format, -1 /*width*/, -1 /*height*/);
}
- /**
- * @hide
- */
- protected ImageWriter(Surface surface, int maxImages, int format, int width, int height) {
+ private void initializeImageWriter(Surface surface, int maxImages,
+ boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat,
+ int hardwareBufferFormat, long dataSpace, int width, int height, long usage) {
if (surface == null || maxImages < 1) {
throw new IllegalArgumentException("Illegal input argument: surface " + surface
- + ", maxImages: " + maxImages);
+ + ", maxImages: " + maxImages);
}
- mMaxImages = maxImages;
-
+ mUseSurfaceImageFormatInfo = useSurfaceImageFormatInfo;
+ mUseLegacyImageFormat = useLegacyImageFormat;
// Note that the underlying BufferQueue is working in synchronous mode
// to avoid dropping any buffers.
- mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format, width,
- height);
+ mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height,
+ useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage);
- // nativeInit internally overrides UNKNOWN format. So does surface format query after
- // nativeInit and before getEstimatedNativeAllocBytes().
- if (format == ImageFormat.UNKNOWN) {
- format = SurfaceUtils.getSurfaceFormat(surface);
- }
- // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
- // allocation estimation sequence depends on the public formats values. To avoid
- // possible errors, convert where necessary.
- if (format == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
- int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
- switch (surfaceDataspace) {
- case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
- format = ImageFormat.DEPTH_POINT_CLOUD;
- break;
- case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
- format = ImageFormat.DEPTH_JPEG;
- break;
- case StreamConfigurationMap.HAL_DATASPACE_HEIF:
- format = ImageFormat.HEIC;
- break;
- default:
- format = ImageFormat.JPEG;
+ if (useSurfaceImageFormatInfo) {
+ // nativeInit internally overrides UNKNOWN format. So does surface format query after
+ // nativeInit and before getEstimatedNativeAllocBytes().
+ imageFormat = SurfaceUtils.getSurfaceFormat(surface);
+ // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
+ // allocation estimation sequence depends on the public formats values. To avoid
+ // possible errors, convert where necessary.
+ if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
+ int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
+ switch (surfaceDataspace) {
+ case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
+ imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
+ break;
+ case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
+ imageFormat = ImageFormat.DEPTH_JPEG;
+ break;
+ case StreamConfigurationMap.HAL_DATASPACE_HEIF:
+ imageFormat = ImageFormat.HEIC;
+ break;
+ default:
+ imageFormat = ImageFormat.JPEG;
+ }
}
+ mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+ mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
}
// Estimate the native buffer allocation size and register it so it gets accounted for
// during GC. Note that this doesn't include the buffers required by the buffer queue
@@ -282,12 +295,49 @@
// complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some
// size.
Size surfSize = SurfaceUtils.getSurfaceSize(surface);
+ mWidth = width == -1 ? surfSize.getWidth() : width;
+ mHeight = height == -1 ? surfSize.getHeight() : height;
+
mEstimatedNativeAllocBytes =
- ImageUtils.getEstimatedNativeAllocBytes(surfSize.getWidth(),surfSize.getHeight(),
- format, /*buffer count*/ 1);
+ ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+ useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
}
+ private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
+ int imageFormat, int width, int height) {
+ mMaxImages = maxImages;
+ // update hal format and dataspace only if image format is overridden by producer.
+ mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+ mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+
+ initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
+ imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage);
+ }
+
+ private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
+ int imageFormat, int width, int height, long usage) {
+ mMaxImages = maxImages;
+ mUsage = usage;
+ mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+ mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+
+ initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
+ imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage);
+ }
+
+ private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
+ int hardwareBufferFormat, long dataSpace, int width, int height, long usage) {
+ mMaxImages = maxImages;
+ mUsage = usage;
+ mHardwareBufferFormat = hardwareBufferFormat;
+ mDataSpace = dataSpace;
+ int publicFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
+
+ initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false,
+ publicFormat, hardwareBufferFormat, dataSpace, width, height, usage);
+ }
+
/**
* <p>
* Maximum number of Images that can be dequeued from the ImageWriter
@@ -316,6 +366,30 @@
}
/**
+ * The width of {@link Image Images}, in pixels.
+ *
+ * <p>If {@link Builder#setWidthAndHeight} is not called, the default width of the Image
+ * depends on the Surface provided by customer end-point.</p>
+ *
+ * @return the expected actual width of an Image.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * The height of {@link Image Images}, in pixels.
+ *
+ * <p>If {@link Builder#setWidthAndHeight} is not called, the default height of the Image
+ * depends on the Surface provided by customer end-point.</p>
+ *
+ * @return the expected height of an Image.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
* <p>
* Dequeue the next available input Image for the application to produce
* data into.
@@ -490,6 +564,41 @@
}
/**
+ * Get the ImageWriter usage flag.
+ *
+ * @return The ImageWriter usage flag.
+ */
+ public @Usage long getUsage() {
+ return mUsage;
+ }
+
+ /**
+ * Get the ImageWriter hardwareBuffer format.
+ *
+ * <p>Use this function if the ImageWriter instance is created by builder pattern
+ * {@code ImageWriter.Builder} and using {@link Builder#setHardwareBufferFormat} and
+ * {@link Builder#setDataSpace}.</p>
+ *
+ * @return The ImageWriter hardwareBuffer format.
+ */
+ public @HardwareBuffer.Format int getHardwareBufferFormat() {
+ return mHardwareBufferFormat;
+ }
+
+ /**
+ * Get the ImageWriter dataspace.
+ *
+ * <p>Use this function if the ImageWriter instance is created by builder pattern
+ * {@code ImageWriter.Builder} and {@link Builder#setDataSpace}.</p>
+ *
+ * @return The ImageWriter dataspace.
+ */
+ @SuppressLint("MethodNameUnits")
+ public @NamedDataSpace long getDataSpace() {
+ return mDataSpace;
+ }
+
+ /**
* ImageWriter callback interface, used to to asynchronously notify the
* application of various ImageWriter events.
*/
@@ -755,6 +864,155 @@
return true;
}
+ /**
+ * Builder class for {@link ImageWriter} objects.
+ */
+ public static final class Builder {
+ private Surface mSurface;
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private int mMaxImages = 1;
+ private int mImageFormat = ImageFormat.UNKNOWN;
+ private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
+ private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
+ private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
+ private boolean mUseSurfaceImageFormatInfo = true;
+ // set this as true temporarily now as a workaround to get correct format
+ // when using surface format by default without overriding the image format
+ // in the builder pattern
+ private boolean mUseLegacyImageFormat = true;
+
+ /**
+ * Constructs a new builder for {@link ImageWriter}.
+ *
+ * @param surface The destination Surface this writer produces Image data into.
+ */
+ public Builder(@NonNull Surface surface) {
+ mSurface = surface;
+ }
+
+ /**
+ * Set the width and height of images. Default size is dependent on the Surface that is
+ * provided by the downstream end-point.
+ *
+ * @param width The width in pixels that will be passed to the producer.
+ * @param height The height in pixels that will be passed to the producer.
+ * @return the Builder instance with customized width and height.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder setWidthAndHeight(@IntRange(from = 1) int width,
+ @IntRange(from = 1) int height) {
+ mWidth = width;
+ mHeight = height;
+ return this;
+ }
+
+ /**
+ * Set the maximum number of images. Default value is 1.
+ *
+ * @param maxImages The maximum number of Images the user will want to access simultaneously
+ * for producing Image data.
+ * @return the Builder instance with customized usage value.
+ */
+ public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) {
+ mMaxImages = maxImages;
+ return this;
+ }
+
+ /**
+ * Set the image format of this ImageWriter.
+ * Default format depends on the Surface provided.
+ *
+ * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified
+ * by {@link ImageFormat} or {@link PixelFormat}.
+ * @return the Builder instance with customized image format.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder setImageFormat(@Format int imageFormat) {
+ if (!ImageFormat.isPublicFormat(imageFormat)
+ && !PixelFormat.isPublicFormat(imageFormat)) {
+ throw new IllegalArgumentException(
+ "Invalid imageFormat is specified: " + imageFormat);
+ }
+ mImageFormat = imageFormat;
+ mUseLegacyImageFormat = true;
+ mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
+ mDataSpace = DataSpace.DATASPACE_UNKNOWN;
+ mUseSurfaceImageFormatInfo = false;
+ return this;
+ }
+
+ /**
+ * Set the hardwareBuffer format of this ImageWriter. The default value is
+ * {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}.
+ *
+ * <p>This function works together with {@link #setDataSpace} for an
+ * {@link ImageWriter} instance. Setting at least one of these two replaces
+ * {@link #setImageFormat} function.</p>
+ *
+ * @param hardwareBufferFormat The HardwareBuffer format of the image that this writer
+ * will produce.
+ * @return the Builder instance with customized buffer format.
+ *
+ * @see #setDataSpace
+ * @see #setImageFormat
+ */
+ public @NonNull Builder setHardwareBufferFormat(
+ @HardwareBuffer.Format int hardwareBufferFormat) {
+ mHardwareBufferFormat = hardwareBufferFormat;
+ mImageFormat = ImageFormat.UNKNOWN;
+ mUseLegacyImageFormat = false;
+ mUseSurfaceImageFormatInfo = false;
+ return this;
+ }
+
+ /**
+ * Set the dataspace of this ImageWriter.
+ * The default value is {@link DataSpace#DATASPACE_UNKNOWN}.
+ *
+ * @param dataSpace The dataspace of the image that this writer will produce.
+ * @return the builder instance with customized dataspace value.
+ *
+ * @see #setHardwareBufferFormat
+ */
+ public @NonNull Builder setDataSpace(@NamedDataSpace long dataSpace) {
+ mDataSpace = dataSpace;
+ mImageFormat = ImageFormat.UNKNOWN;
+ mUseLegacyImageFormat = false;
+ mUseSurfaceImageFormatInfo = false;
+ return this;
+ }
+
+ /**
+ * Set the usage flag of this ImageWriter.
+ * Default value is {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN}.
+ *
+ * @param usage The intended usage of the images produced by this ImageWriter.
+ * @return the Builder instance with customized usage flag.
+ *
+ * @see HardwareBuffer
+ */
+ public @NonNull Builder setUsage(@Usage long usage) {
+ mUsage = usage;
+ return this;
+ }
+
+ /**
+ * Builds a new ImageWriter object.
+ *
+ * @return The new ImageWriter object.
+ */
+ public @NonNull ImageWriter build() {
+ if (mUseLegacyImageFormat) {
+ return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
+ mImageFormat, mWidth, mHeight, mUsage);
+ } else {
+ return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
+ mHardwareBufferFormat, mDataSpace, mWidth, mHeight, mUsage);
+ }
+ }
+ }
+
private static class WriterSurfaceImage extends android.media.Image {
private ImageWriter mOwner;
// This field is used by native code, do not access or modify.
@@ -774,6 +1032,13 @@
public WriterSurfaceImage(ImageWriter writer) {
mOwner = writer;
+ mWidth = writer.mWidth;
+ mHeight = writer.mHeight;
+
+ if (!writer.mUseLegacyImageFormat) {
+ mFormat = PublicFormatUtils.getPublicFormat(
+ writer.mHardwareBufferFormat, writer.mDataSpace);
+ }
}
@Override
@@ -969,8 +1234,9 @@
}
// Native implemented ImageWriter methods.
- private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs,
- int format, int width, int height);
+ private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImages,
+ int width, int height, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat,
+ long dataSpace, long usage);
private synchronized native void nativeClose(long nativeCtx);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 3c152fb..e75df1d 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -603,6 +603,18 @@
public static final String FEATURE_QpBounds = "qp-bounds";
/**
+ * <b>video encoder only</b>: codec supports exporting encoding statistics.
+ * Encoders with this feature can provide the App clients with the encoding statistics
+ * information about the frame.
+ * The scope of encoding statistics is controlled by
+ * {@link MediaFormat#KEY_VIDEO_ENCODING_STATISTICS_LEVEL}.
+ *
+ * @see MediaFormat#KEY_VIDEO_ENCODING_STATISTICS_LEVEL
+ */
+ @SuppressLint("AllUpper") // for consistency with other FEATURE_* constants
+ public static final String FEATURE_EncodingStatistics = "encoding-statistics";
+
+ /**
* Query codec feature capabilities.
* <p>
* These features are supported to be used by the codec. These
@@ -641,6 +653,7 @@
new Feature(FEATURE_MultipleFrames, (1 << 1), false),
new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
new Feature(FEATURE_QpBounds, (1 << 3), false),
+ new Feature(FEATURE_EncodingStatistics, (1 << 4), false),
// feature to exclude codec from REGULAR codec list
new Feature(FEATURE_SpecialCodec, (1 << 30), false, true),
};
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4891d74..4956dbe 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1176,6 +1176,76 @@
public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
/**
+ * A key describing the level of encoding statistics information emitted from video encoder.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_ENCODING_STATISTICS_LEVEL =
+ "video-encoding-statistics-level";
+
+ /**
+ * Encoding Statistics Level None.
+ * Encoder generates no information about Encoding statistics.
+ */
+ public static final int VIDEO_ENCODING_STATISTICS_LEVEL_NONE = 0;
+
+ /**
+ * Encoding Statistics Level 1.
+ * Encoder generates {@link MediaFormat#KEY_PICTURE_TYPE} and
+ * {@link MediaFormat#KEY_VIDEO_QP_AVERAGE} for each frame.
+ */
+ public static final int VIDEO_ENCODING_STATISTICS_LEVEL_1 = 1;
+
+ /** @hide */
+ @IntDef({
+ VIDEO_ENCODING_STATISTICS_LEVEL_NONE,
+ VIDEO_ENCODING_STATISTICS_LEVEL_1,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VideoEncodingStatisticsLevel {}
+
+ /**
+ * A key describing the per-frame average block QP (Quantization Parameter).
+ * This is a part of a video 'Encoding Statistics' export feature.
+ * This value is emitted from video encoder for a video frame.
+ * The average value is rounded down (using floor()) to integer value.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_AVERAGE = "video-qp-average";
+
+ /**
+ * A key describing the picture type of the encoded frame.
+ * This is a part of a video 'Encoding Statistics' export feature.
+ * This value is emitted from video encoder for a video frame.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_PICTURE_TYPE = "picture-type";
+
+ /** Picture Type is unknown. */
+ public static final int PICTURE_TYPE_UNKNOWN = 0;
+
+ /** Picture Type is I Frame. */
+ public static final int PICTURE_TYPE_I = 1;
+
+ /** Picture Type is P Frame. */
+ public static final int PICTURE_TYPE_P = 2;
+
+ /** Picture Type is B Frame. */
+ public static final int PICTURE_TYPE_B = 3;
+
+ /** @hide */
+ @IntDef({
+ PICTURE_TYPE_UNKNOWN,
+ PICTURE_TYPE_I,
+ PICTURE_TYPE_P,
+ PICTURE_TYPE_B,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PictureType {}
+
+ /**
* A key describing the audio session ID of the AudioTrack associated
* to a tunneled video codec.
* The associated value is an integer.
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index a049a88..831649e 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -31,12 +31,15 @@
import android.os.RemoteException;
import android.util.Log;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
+// BLE-MIDI
+
/**
* This class is the public application interface to the MIDI service.
*/
@@ -399,9 +402,11 @@
final OnDeviceOpenedListener listenerF = listener;
final Handler handlerF = handler;
+ Log.d(TAG, "openBluetoothDevice() " + bluetoothDevice);
IMidiDeviceOpenCallback callback = new IMidiDeviceOpenCallback.Stub() {
@Override
public void onDeviceOpened(IMidiDeviceServer server, IBinder deviceToken) {
+ Log.d(TAG, "onDeviceOpened() server:" + server);
MidiDevice device = null;
if (server != null) {
try {
@@ -423,6 +428,15 @@
}
}
+ /** @hide */ // for now
+ public void closeBluetoothDevice(@NonNull MidiDevice midiDevice) {
+ try {
+ midiDevice.close();
+ } catch (IOException ex) {
+ Log.e(TAG, "Exception closing BLE-MIDI device" + ex);
+ }
+ }
+
/** @hide */
public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers,
int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index ff4c625..71b1634 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -17,11 +17,12 @@
package android.media.tv;
import android.annotation.NonNull;
+import android.media.tv.interactive.TvInteractiveAppInfo;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * AIT info.
+ * AIT (Application Information Table) info.
* @hide
*/
public final class AitInfo implements Parcelable {
@@ -50,14 +51,15 @@
/**
* Constructs AIT info.
*/
- public AitInfo(int type, int version) {
+ public AitInfo(@TvInteractiveAppInfo.InteractiveAppType int type, int version) {
mType = type;
mVersion = version;
}
/**
- * Gets type.
+ * Gets interactive app type.
*/
+ @TvInteractiveAppInfo.InteractiveAppType
public int getType() {
return mType;
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 98d1599..f438d29 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -31,7 +31,7 @@
import android.media.AudioDeviceInfo;
import android.media.AudioFormat.Encoding;
import android.media.PlaybackParams;
-import android.media.tv.interactive.TvIAppManager;
+import android.media.tv.interactive.TvInteractiveAppManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -2318,7 +2318,7 @@
// @GuardedBy("mMetadataLock")
private int mVideoHeight;
- private TvIAppManager.Session mIAppSession;
+ private TvInteractiveAppManager.Session mIAppSession;
private boolean mIAppNotificationEnabled = false;
private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
@@ -2331,11 +2331,11 @@
mSessionCallbackRecordMap = sessionCallbackRecordMap;
}
- public TvIAppManager.Session getInteractiveAppSession() {
+ public TvInteractiveAppManager.Session getInteractiveAppSession() {
return mIAppSession;
}
- public void setInteractiveAppSession(TvIAppManager.Session iAppSession) {
+ public void setInteractiveAppSession(TvInteractiveAppManager.Session iAppSession) {
this.mIAppSession = iAppSession;
}
@@ -2593,9 +2593,9 @@
/**
* Enables interactive app notification.
+ *
* @param enabled {@code true} if you want to enable interactive app notifications.
* {@code false} otherwise.
- * @hide
*/
public void setInteractiveAppNotificationEnabled(boolean enabled) {
if (mToken == null) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 524ba34..9bc7367 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -945,7 +945,13 @@
}
/**
- * Notifies AIT info updated.
+ * Informs the app that the AIT (Application Information Table) is updated.
+ *
+ * <p>This method should also be call when
+ * {@link #onSetInteractiveAppNotificationEnabled(boolean)} is called to send the first AIT
+ * info.
+ *
+ * @see #onSetInteractiveAppNotificationEnabled(boolean)
* @hide
*/
public void notifyAitInfoUpdated(@NonNull final AitInfo aitInfo) {
@@ -1198,7 +1204,16 @@
/**
* Enables or disables interactive app notification.
+ *
+ * <p>This method enables or disables the event detection from the corresponding TV input.
+ * When it's enabled, the TV input service detects events related to interactive app, such
+ * as AIT (Application Information Table) and sends to TvView or the linked TV interactive
+ * app service.
+ *
* @param enabled {@code true} to enable, {@code false} to disable.
+ *
+ * @see TvView#setInteractiveAppNotificationEnabled(boolean)
+ * @see Session#notifyAitInfoUpdated(android.media.tv.AitInfo)
* @hide
*/
public void onSetInteractiveAppNotificationEnabled(boolean enabled) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 71f6ad6..d2086c5 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -481,9 +481,18 @@
}
/**
- * Enables interactive app notification.
+ * Enables or disables interactive app notification.
+ *
+ * <p>This method enables or disables the event detection from the corresponding TV input. When
+ * it's enabled, the TV input service detects events related to interactive app, such as
+ * AIT (Application Information Table) and sends to TvView or the linked TV interactive app
+ * service.
+ *
* @param enabled {@code true} if you want to enable interactive app notifications.
* {@code false} otherwise.
+ *
+ * @see TvInputService.Session#notifyAitInfoUpdated(android.media.tv.AitInfo)
+ * @see android.media.tv.interactive.TvInteractiveAppView#setTvView(TvView)
* @hide
*/
public void setInteractiveAppNotificationEnabled(boolean enabled) {
@@ -1062,12 +1071,12 @@
}
/**
- * This is called when the AIT info has been updated.
+ * This is called when the AIT (Application Information Table) info has been updated.
*
* @param aitInfo The current AIT info.
* @hide
*/
- public void onAitInfoUpdated(String inputId, AitInfo aitInfo) {
+ public void onAitInfoUpdated(@NonNull String inputId, @NonNull AitInfo aitInfo) {
}
/**
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 1a8fc46..a3e58d1 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -34,7 +34,7 @@
void onLayoutSurface(int left, int top, int right, int bottom, int seq);
void onBroadcastInfoRequest(in BroadcastInfoRequest request, int seq);
void onRemoveBroadcastInfo(int id, int seq);
- void onSessionStateChanged(int state, int seq);
+ void onSessionStateChanged(int state, int err, int seq);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
void onTeletextAppStateChanged(int state, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
similarity index 98%
rename from media/java/android/media/tv/interactive/ITvIAppManager.aidl
rename to media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index a19a2d2..a8ef095 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -31,7 +31,7 @@
* Interface to the TV interactive app service.
* @hide
*/
-interface ITvIAppManager {
+interface ITvInteractiveAppManager {
List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
void prepare(String tiasId, int type, int userId);
void registerAppLinkInfo(String tiasId, in Bundle info, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index f4510f6..23be4c6 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -27,5 +27,5 @@
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
- void onStateChanged(in String iAppServiceId, int type, int state);
+ void onStateChanged(in String iAppServiceId, int type, int state, int err);
}
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
index c1e6622..68fae2d 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
@@ -23,7 +23,7 @@
/**
* Top-level interface to a TV Interactive App component (implemented in a Service). It's used for
- * TvIAppManagerService to communicate with TvIAppService.
+ * TvInteractiveAppManagerService to communicate with TvInteractiveAppService.
* @hide
*/
oneway interface ITvInteractiveAppService {
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
index f56d3bd..970b943 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
@@ -17,10 +17,10 @@
package android.media.tv.interactive;
/**
- * Helper interface for ITvInteractiveAppService to allow the TvIAppService to notify the
- * TvIAppManagerService.
+ * Helper interface for ITvInteractiveAppService to allow the TvInteractiveAppService to notify the
+ * TvInteractiveAppManagerService.
* @hide
*/
oneway interface ITvInteractiveAppServiceCallback {
- void onStateChanged(int type, int state);
+ void onStateChanged(int type, int state, int error);
}
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index c270424..385f0d4 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -24,7 +24,7 @@
import android.os.Bundle;
/**
- * Helper interface for ITvInteractiveAppSession to allow TvIAppService to notify the
+ * Helper interface for ITvInteractiveAppSession to allow TvInteractiveAppService to notify the
* system service when there is a related event.
* @hide
*/
@@ -33,7 +33,7 @@
void onLayoutSurface(int left, int top, int right, int bottom);
void onBroadcastInfoRequest(in BroadcastInfoRequest request);
void onRemoveBroadcastInfo(int id);
- void onSessionStateChanged(int state);
+ void onSessionStateChanged(int state, int err);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
void onTeletextAppStateChanged(int state);
void onCommandRequest(in String cmdType, in Bundle parameters);
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
index 2f96552..e1f535c 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
@@ -44,7 +44,6 @@
/**
* This class is used to specify meta information of a TV interactive app.
- * @hide
*/
public final class TvInteractiveAppInfo implements Parcelable {
private static final boolean DEBUG = false;
@@ -59,7 +58,7 @@
INTERACTIVE_APP_TYPE_ATSC,
INTERACTIVE_APP_TYPE_GINGA,
})
- @interface InteractiveAppType {}
+ public @interface InteractiveAppType {}
/** HbbTV interactive app type */
public static final int INTERACTIVE_APP_TYPE_HBBTV = 0x1;
@@ -77,7 +76,7 @@
throw new IllegalArgumentException("context cannot be null.");
}
Intent intent =
- new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
+ new Intent(TvInteractiveAppService.SERVICE_INTERFACE).setComponent(component);
ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
if (resolveInfo == null) {
@@ -171,10 +170,10 @@
ServiceInfo si = resolveInfo.serviceInfo;
PackageManager pm = context.getPackageManager();
try (XmlResourceParser parser =
- si.loadXmlMetaData(pm, TvIAppService.SERVICE_META_DATA)) {
+ si.loadXmlMetaData(pm, TvInteractiveAppService.SERVICE_META_DATA)) {
if (parser == null) {
throw new IllegalStateException(
- "No " + TvIAppService.SERVICE_META_DATA
+ "No " + TvInteractiveAppService.SERVICE_META_DATA
+ " meta-data found for " + si.name);
}
@@ -194,9 +193,9 @@
}
TypedArray sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.TvIAppService);
+ com.android.internal.R.styleable.TvInteractiveAppService);
CharSequence[] textArr = sa.getTextArray(
- com.android.internal.R.styleable.TvIAppService_supportedTypes);
+ com.android.internal.R.styleable.TvInteractiveAppService_supportedTypes);
for (CharSequence cs : textArr) {
types.add(cs.toString().toLowerCase());
}
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
similarity index 87%
rename from media/java/android/media/tv/interactive/TvIAppManager.java
rename to media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index f819438..15a5f823 100755
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -16,6 +16,7 @@
package android.media.tv.interactive;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,45 +53,128 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Central system API to the overall TV interactive application framework (TIAF) architecture, which
* arbitrates interaction between applications and interactive apps.
*/
-@SystemService(Context.TV_IAPP_SERVICE)
-public final class TvIAppManager {
+@SystemService(Context.TV_INTERACTIVE_APP_SERVICE)
+public final class TvInteractiveAppManager {
// TODO: cleanup and unhide public APIs
- private static final String TAG = "TvIAppManager";
+ private static final String TAG = "TvInteractiveAppManager";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, prefix = "TV_INTERACTIVE_APP_RTE_STATE_", value = {
- TV_INTERACTIVE_APP_RTE_STATE_UNREALIZED,
- TV_INTERACTIVE_APP_RTE_STATE_PREPARING,
- TV_INTERACTIVE_APP_RTE_STATE_READY,
- TV_INTERACTIVE_APP_RTE_STATE_ERROR})
- public @interface TvInteractiveAppRteState {}
+ @IntDef(flag = false, prefix = "SERVICE_STATE_", value = {
+ SERVICE_STATE_UNREALIZED,
+ SERVICE_STATE_PREPARING,
+ SERVICE_STATE_READY,
+ SERVICE_STATE_ERROR})
+ public @interface ServiceState {}
/**
- * Unrealized state of interactive app RTE.
+ * Unrealized state of interactive app service.
* @hide
*/
- public static final int TV_INTERACTIVE_APP_RTE_STATE_UNREALIZED = 1;
+ public static final int SERVICE_STATE_UNREALIZED = 1;
/**
- * Preparing state of interactive app RTE.
+ * Preparing state of interactive app service.
* @hide
*/
- public static final int TV_INTERACTIVE_APP_RTE_STATE_PREPARING = 2;
+ public static final int SERVICE_STATE_PREPARING = 2;
/**
- * Ready state of interactive app RTE.
+ * Ready state of interactive app service.
* @hide
*/
- public static final int TV_INTERACTIVE_APP_RTE_STATE_READY = 3;
+ public static final int SERVICE_STATE_READY = 3;
/**
- * Error state of interactive app RTE.
+ * Error state of interactive app service.
* @hide
*/
- public static final int TV_INTERACTIVE_APP_RTE_STATE_ERROR = 4;
+ public static final int SERVICE_STATE_ERROR = 4;
+
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, prefix = "INTERACTIVE_APP_STATE_", value = {
+ INTERACTIVE_APP_STATE_STOPPED,
+ INTERACTIVE_APP_STATE_RUNNING,
+ INTERACTIVE_APP_STATE_ERROR})
+ public @interface InteractiveAppState {}
+
+ /**
+ * Stopped (or not started) state of interactive application.
+ * @hide
+ */
+ public static final int INTERACTIVE_APP_STATE_STOPPED = 1;
+ /**
+ * Running state of interactive application.
+ * @hide
+ */
+ public static final int INTERACTIVE_APP_STATE_RUNNING = 2;
+ /**
+ * Error state of interactive application.
+ * @hide
+ */
+ public static final int INTERACTIVE_APP_STATE_ERROR = 3;
+
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, prefix = "ERROR_", value = {
+ ERROR_NONE,
+ ERROR_UNKNOWN,
+ ERROR_NOT_SUPPORTED,
+ ERROR_WEAK_SIGNAL,
+ ERROR_RESOURCE_UNAVAILABLE,
+ ERROR_BLOCKED,
+ ERROR_ENCRYPTED,
+ ERROR_UNKNOWN_CHANNEL,
+ })
+ public @interface ErrorCode {}
+
+ /**
+ * No error.
+ * @hide
+ */
+ public static final int ERROR_NONE = 0;
+ /**
+ * Unknown error code.
+ * @hide
+ */
+ public static final int ERROR_UNKNOWN = 1;
+ /**
+ * Error code for an unsupported channel.
+ * @hide
+ */
+ public static final int ERROR_NOT_SUPPORTED = 2;
+ /**
+ * Error code for weak signal.
+ * @hide
+ */
+ public static final int ERROR_WEAK_SIGNAL = 3;
+ /**
+ * Error code when resource (e.g. tuner) is unavailable.
+ * @hide
+ */
+ public static final int ERROR_RESOURCE_UNAVAILABLE = 4;
+ /**
+ * Error code for blocked contents.
+ * @hide
+ */
+ public static final int ERROR_BLOCKED = 5;
+ /**
+ * Error code when the key or module is missing for the encrypted channel.
+ * @hide
+ */
+ public static final int ERROR_ENCRYPTED = 6;
+ /**
+ * Error code when the current channel is an unknown channel.
+ * @hide
+ */
+ public static final int ERROR_UNKNOWN_CHANNEL = 7;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -190,7 +274,7 @@
*/
public static final String KEY_BACK_URI = "back_uri";
- private final ITvIAppManager mService;
+ private final ITvInteractiveAppManager mService;
private final int mUserId;
// A mapping from the sequence number of a session to its SessionCallbackRecord.
@@ -209,7 +293,7 @@
private final ITvInteractiveAppClient mClient;
/** @hide */
- public TvIAppManager(ITvIAppManager service, int userId) {
+ public TvInteractiveAppManager(ITvInteractiveAppManager service, int userId) {
mService = service;
mUserId = userId;
mClient = new ITvInteractiveAppClient.Stub() {
@@ -285,7 +369,7 @@
@Override
public void onCommandRequest(
- @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters,
int seq) {
synchronized (mSessionCallbackRecordMap) {
@@ -383,14 +467,14 @@
}
@Override
- public void onSessionStateChanged(int state, int seq) {
+ public void onSessionStateChanged(int state, int err, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postSessionStateChanged(state);
+ record.postSessionStateChanged(state, err);
}
}
@@ -458,10 +542,10 @@
}
@Override
- public void onStateChanged(String iAppServiceId, int type, int state) {
+ public void onStateChanged(String iAppServiceId, int type, int state, int err) {
synchronized (mLock) {
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
- record.postStateChanged(iAppServiceId, type, state);
+ record.postStateChanged(iAppServiceId, type, state, err);
}
}
}
@@ -484,9 +568,10 @@
* This is called when a TV Interactive App service is added to the system.
*
* <p>Normally it happens when the user installs a new TV Interactive App service package
- * that implements {@link TvIAppService} interface.
+ * that implements {@link TvInteractiveAppService} interface.
*
* @param iAppServiceId The ID of the TV Interactive App service.
+ * @hide
*/
public void onInteractiveAppServiceAdded(@NonNull String iAppServiceId) {
}
@@ -498,6 +583,7 @@
* App service package.
*
* @param iAppServiceId The ID of the TV Interactive App service.
+ * @hide
*/
public void onInteractiveAppServiceRemoved(@NonNull String iAppServiceId) {
}
@@ -509,6 +595,7 @@
* re-installed or a newer version of the package exists becomes available/unavailable.
*
* @param iAppServiceId The ID of the TV Interactive App service.
+ * @hide
*/
public void onInteractiveAppServiceUpdated(@NonNull String iAppServiceId) {
}
@@ -524,26 +611,34 @@
*
* @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
* information.
+ * @hide
*/
public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
}
/**
* This is called when the state of the interactive app service is changed.
- * @hide
+ *
+ * @param type the interactive app type
+ * @param state the current state of the service of the given type
+ * @param err the error code for error state. {@link #ERROR_NONE} is used when the state is
+ * not {@link #SERVICE_STATE_ERROR}.
*/
public void onTvInteractiveAppServiceStateChanged(
- @NonNull String iAppServiceId, int type, @TvInteractiveAppRteState int state) {
+ @NonNull String iAppServiceId,
+ @TvInteractiveAppInfo.InteractiveAppType int type,
+ @ServiceState int state,
+ @ErrorCode int err) {
}
}
private static final class TvInteractiveAppCallbackRecord {
private final TvInteractiveAppCallback mCallback;
- private final Handler mHandler;
+ private final Executor mExecutor;
- TvInteractiveAppCallbackRecord(TvInteractiveAppCallback callback, Handler handler) {
+ TvInteractiveAppCallbackRecord(TvInteractiveAppCallback callback, Executor executor) {
mCallback = callback;
- mHandler = handler;
+ mExecutor = executor;
}
public TvInteractiveAppCallback getCallback() {
@@ -551,7 +646,7 @@
}
public void postInteractiveAppServiceAdded(final String iAppServiceId) {
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
mCallback.onInteractiveAppServiceAdded(iAppServiceId);
@@ -560,7 +655,7 @@
}
public void postInteractiveAppServiceRemoved(final String iAppServiceId) {
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
mCallback.onInteractiveAppServiceRemoved(iAppServiceId);
@@ -569,7 +664,7 @@
}
public void postInteractiveAppServiceUpdated(final String iAppServiceId) {
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
mCallback.onInteractiveAppServiceUpdated(iAppServiceId);
@@ -578,7 +673,7 @@
}
public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
@@ -586,11 +681,12 @@
});
}
- public void postStateChanged(String iAppServiceId, int type, int state) {
- mHandler.post(new Runnable() {
+ public void postStateChanged(String iAppServiceId, int type, int state, int err) {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mCallback.onTvInteractiveAppServiceStateChanged(iAppServiceId, type, state);
+ mCallback.onTvInteractiveAppServiceStateChanged(
+ iAppServiceId, type, state, err);
}
});
}
@@ -635,7 +731,6 @@
*
* @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
* describes its meta information.
- * @hide
*/
@NonNull
public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
@@ -699,15 +794,16 @@
* Registers a {@link TvInteractiveAppCallback}.
*
* @param callback A callback used to monitor status of the TV Interactive App services.
- * @param handler A {@link Handler} that the status change will be delivered to.
+ * @param executor A {@link Executor} that the status change will be delivered to.
* @hide
*/
public void registerCallback(
- @NonNull TvInteractiveAppCallback callback, @NonNull Handler handler) {
+ @NonNull TvInteractiveAppCallback callback,
+ @CallbackExecutor @NonNull Executor executor) {
Preconditions.checkNotNull(callback);
- Preconditions.checkNotNull(handler);
+ Preconditions.checkNotNull(executor);
synchronized (mLock) {
- mCallbackRecords.add(new TvInteractiveAppCallbackRecord(callback, handler));
+ mCallbackRecords.add(new TvInteractiveAppCallbackRecord(callback, executor));
}
}
@@ -742,7 +838,7 @@
private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
- private final ITvIAppManager mService;
+ private final ITvInteractiveAppManager mService;
private final int mUserId;
private final int mSeq;
private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
@@ -759,7 +855,7 @@
private TvInputEventSender mSender;
private InputChannel mInputChannel;
- private Session(IBinder token, InputChannel channel, ITvIAppManager service,
+ private Session(IBinder token, InputChannel channel, ITvInteractiveAppManager service,
int userId, int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
mToken = token;
mInputChannel = channel;
@@ -1142,7 +1238,7 @@
}
/**
- * Notifies IAPP session when video is available.
+ * Notifies Interactive APP session when video is available.
*/
public void notifyVideoAvailable() {
if (mToken == null) {
@@ -1157,7 +1253,7 @@
}
/**
- * Notifies IAPP session when video is unavailable.
+ * Notifies Interactive APP session when video is unavailable.
*/
public void notifyVideoUnavailable(int reason) {
if (mToken == null) {
@@ -1172,7 +1268,7 @@
}
/**
- * Notifies IAPP session when content is allowed.
+ * Notifies Interactive APP session when content is allowed.
*/
public void notifyContentAllowed() {
if (mToken == null) {
@@ -1187,7 +1283,7 @@
}
/**
- * Notifies IAPP session when content is blocked.
+ * Notifies Interactive APP session when content is blocked.
*/
public void notifyContentBlocked(TvContentRating rating) {
if (mToken == null) {
@@ -1478,7 +1574,7 @@
}
void postCommandRequest(
- final @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ final @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
final Bundle parameters) {
mHandler.post(new Runnable() {
@Override
@@ -1553,11 +1649,11 @@
});
}
- void postSessionStateChanged(int state) {
+ void postSessionStateChanged(int state, int err) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onSessionStateChanged(mSession, state);
+ mSessionCallback.onSessionStateChanged(mSession, state, err);
}
});
}
@@ -1587,28 +1683,28 @@
*/
public abstract static class SessionCallback {
/**
- * This is called after {@link TvIAppManager#createSession} has been processed.
+ * This is called after {@link TvInteractiveAppManager#createSession} has been processed.
*
- * @param session A {@link TvIAppManager.Session} instance created. This can be
+ * @param session A {@link TvInteractiveAppManager.Session} instance created. This can be
* {@code null} if the creation request failed.
*/
public void onSessionCreated(@Nullable Session session) {
}
/**
- * This is called when {@link TvIAppManager.Session} is released.
+ * This is called when {@link TvInteractiveAppManager.Session} is released.
* This typically happens when the process hosting the session has crashed or been killed.
*
- * @param session the {@link TvIAppManager.Session} instance released.
+ * @param session the {@link TvInteractiveAppManager.Session} instance released.
*/
public void onSessionReleased(@NonNull Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#layoutSurface} is called to
+ * This is called when {@link TvInteractiveAppService.Session#layoutSurface} is called to
* change the layout of surface.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param left Left position.
* @param top Top position.
* @param right Right position.
@@ -1618,85 +1714,90 @@
}
/**
- * This is called when {@link TvIAppService.Session#requestCommand} is called.
+ * This is called when {@link TvInteractiveAppService.Session#requestCommand} is called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param cmdType type of the command.
* @param parameters parameters of the command.
*/
public void onCommandRequest(
Session session,
- @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
}
/**
- * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+ * This is called when {@link TvInteractiveAppService.Session#SetVideoBounds} is called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
*/
public void onSetVideoBounds(Session session, Rect rect) {
}
/**
- * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelUri} is
* called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
*/
public void onRequestCurrentChannelUri(Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelLcn} is
* called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
*/
public void onRequestCurrentChannelLcn(Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#RequestStreamVolume} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestStreamVolume} is
* called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
*/
public void onRequestStreamVolume(Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestTrackInfoList} is
* called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
*/
public void onRequestTrackInfoList(Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#RequestCurrentTvInputId} is called.
+ * This is called when {@link TvInteractiveAppService.Session#RequestCurrentTvInputId} is
+ * called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
* @hide
*/
public void onRequestCurrentTvInputId(Session session) {
}
/**
- * This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
+ * This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
+ * called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param state the current state.
*/
- public void onSessionStateChanged(Session session, int state) {
+ public void onSessionStateChanged(
+ Session session,
+ @InteractiveAppState int state,
+ @ErrorCode int err) {
}
/**
- * This is called when {@link TvIAppService.Session#notifyBiInteractiveAppCreated}
+ * This is called when {@link TvInteractiveAppService.Session#notifyBiInteractiveAppCreated}
* is called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param biIAppUri URI associated this BI interactive app. This is the same URI in
* {@link Session#createBiInteractiveApp(Uri, Bundle)}
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
@@ -1709,11 +1810,11 @@
* This is called when {@link TvIAppService.Session#notifyTeletextAppStateChanged} is
* called.
*
- * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param state the current state.
*/
public void onTeletextAppStateChanged(
- Session session, @TvIAppManager.TeletextAppState int state) {
+ Session session, @TvInteractiveAppManager.TeletextAppState int state) {
}
}
}
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
similarity index 93%
rename from media/java/android/media/tv/interactive/TvIAppService.java
rename to media/java/android/media/tv/interactive/TvInteractiveAppService.java
index c0ec76b..094aabd 100755
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -65,11 +65,11 @@
import java.util.List;
/**
- * The TvIAppService class represents a TV interactive applications RTE.
+ * The TvInteractiveAppService class represents a TV interactive applications RTE.
*/
-public abstract class TvIAppService extends Service {
+public abstract class TvInteractiveAppService extends Service {
private static final boolean DEBUG = false;
- private static final String TAG = "TvIAppService";
+ private static final String TAG = "TvInteractiveAppService";
private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
@@ -83,12 +83,12 @@
* cannot abuse it.
*/
public static final String SERVICE_INTERFACE =
- "android.media.tv.interactive.TvIAppService";
+ "android.media.tv.interactive.TvInteractiveAppService";
/**
- * Name under which a TvIAppService component publishes information about itself. This
+ * Name under which a TvInteractiveAppService component publishes information about itself. This
* meta-data must reference an XML resource containing an
- * <code><{@link android.R.styleable#TvIAppService tv-interactive-app}></code>
+ * <code><{@link android.R.styleable#TvInteractiveAppService tv-interactive-app}></code>
* tag.
*/
public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
@@ -196,8 +196,7 @@
* Prepares TV Interactive App service for the given type.
* @hide
*/
- public void onPrepare(int type) {
- // TODO: make it abstract when unhide
+ public void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type) {
}
/**
@@ -236,20 +235,32 @@
* @hide
*/
@Nullable
- public Session onCreateSession(@NonNull String iAppServiceId, int type) {
- // TODO: make it abstract when unhide
+ public Session onCreateSession(
+ @NonNull String iAppServiceId,
+ @TvInteractiveAppInfo.InteractiveAppType int type) {
return null;
}
/**
- * Notifies the system when the state of the interactive app has been changed.
- * @param state the current state
+ * Notifies the system when the state of the interactive app RTE has been changed.
+ *
+ * @param type the interactive app type
+ * @param state the current state of the service of the given type
+ * @param error the error code for error state. {@link TvInteractiveAppManager#ERROR_NONE} is
+ * used when the state is not
+ * {@link TvInteractiveAppManager#SERVICE_STATE_ERROR}.
* @hide
*/
public final void notifyStateChanged(
- int type, @TvIAppManager.TvInteractiveAppRteState int state) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_RTE_STATE_CHANGED,
- type, state).sendToTarget();
+ @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppManager.ServiceState int state,
+ @TvInteractiveAppManager.ErrorCode int error) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = type;
+ args.arg2 = state;
+ args.arg3 = error;
+ mServiceHandler
+ .obtainMessage(ServiceHandler.DO_NOTIFY_RTE_STATE_CHANGED, args).sendToTarget();
}
/**
@@ -298,6 +309,7 @@
*
* @param enable {@code true} if you want to enable the media view. {@code false}
* otherwise.
+ * @hide
*/
public void setMediaViewEnabled(final boolean enable) {
mHandler.post(new Runnable() {
@@ -319,15 +331,13 @@
}
/**
- * Starts TvIAppService session.
- * @hide
+ * Starts TvInteractiveAppService session.
*/
public void onStartInteractiveApp() {
}
/**
- * Stops TvIAppService session.
- * @hide
+ * Stops TvInteractiveAppService session.
*/
public void onStopInteractiveApp() {
}
@@ -364,6 +374,7 @@
/**
* To toggle Digital Teletext Application if there is one in AIT app list.
* @param enable
+ * @hide
*/
public void onSetTeletextAppEnabled(boolean enable) {
}
@@ -438,6 +449,7 @@
*
* @param width The width of the media view.
* @param height The height of the media view.
+ * @hide
*/
public void onMediaViewSizeChanged(int width, int height) {
}
@@ -447,6 +459,7 @@
* implementation can override this method and return its own view.
*
* @return a view attached to the media window
+ * @hide
*/
@Nullable
public View onCreateMediaView() {
@@ -454,7 +467,7 @@
}
/**
- * Releases TvIAppService session.
+ * Releases TvInteractiveAppService session.
* @hide
*/
public void onRelease() {
@@ -620,6 +633,7 @@
/**
* Requests broadcast related information from the related TV input.
* @param request the request for broadcast info
+ * @hide
*/
public void requestBroadcastInfo(@NonNull final BroadcastInfoRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -644,6 +658,7 @@
/**
* Remove broadcast information request from the related TV input.
* @param requestId the ID of the request
+ * @hide
*/
public void removeBroadcastInfo(final int requestId) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -669,6 +684,7 @@
* requests a specific command to be processed by the related TV input.
* @param cmdType type of the specific command
* @param parameters parameters of the specific command
+ * @hide
*/
public void requestCommand(
@InteractiveAppServiceCommandType String cmdType, Bundle parameters) {
@@ -693,6 +709,7 @@
/**
* Sets broadcast video bounds.
+ * @hide
*/
public void setVideoBounds(Rect rect) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -715,6 +732,7 @@
/**
* Requests the URI of the current channel.
+ * @hide
*/
public void requestCurrentChannelUri() {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -737,6 +755,7 @@
/**
* Requests the logic channel number (LCN) of the current channel.
+ * @hide
*/
public void requestCurrentChannelLcn() {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -759,6 +778,7 @@
/**
* Requests stream volume.
+ * @hide
*/
public void requestStreamVolume() {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -781,6 +801,7 @@
/**
* Requests the list of {@link TvTrackInfo}.
+ * @hide
*/
public void requestTrackInfoList() {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -829,6 +850,7 @@
/**
* requests an advertisement request to be processed by the related TV input.
* @param request advertisement request
+ * @hide
*/
public void requestAd(@NonNull final AdRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -987,10 +1009,15 @@
/**
* Notifies when the session state is changed.
- * @param state the current state.
+ *
+ * @param state the current session state.
+ * @param err the error code for error state. {@link TvInteractiveAppManager#ERROR_NONE} is
+ * used when the state is not
+ * {@link TvInteractiveAppManager#INTERACTIVE_APP_STATE_ERROR}.
*/
public void notifySessionStateChanged(
- @TvIAppManager.TvInteractiveAppRteState int state) {
+ @TvInteractiveAppManager.InteractiveAppState int state,
+ @TvInteractiveAppManager.ErrorCode int err) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
@@ -998,10 +1025,10 @@
try {
if (DEBUG) {
Log.d(TAG, "notifySessionStateChanged (state="
- + state + ")");
+ + state + "; err=" + err + ")");
}
if (mSessionCallback != null) {
- mSessionCallback.onSessionStateChanged(state);
+ mSessionCallback.onSessionStateChanged(state, err);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifySessionStateChanged", e);
@@ -1039,8 +1066,10 @@
/**
* Notifies when the digital teletext app state is changed.
* @param state the current state.
+ * @hide
*/
- public final void notifyTeletextAppStateChanged(@TvIAppManager.TeletextAppState int state) {
+ public final void notifyTeletextAppStateChanged(
+ @TvInteractiveAppManager.TeletextAppState int state) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
@@ -1068,7 +1097,7 @@
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.dispatch(this, mDispatcherState, this)) {
- return TvIAppManager.Session.DISPATCH_HANDLED;
+ return TvInteractiveAppManager.Session.DISPATCH_HANDLED;
}
// TODO: special handlings of navigation keys and media keys
@@ -1077,20 +1106,20 @@
final int source = motionEvent.getSource();
if (motionEvent.isTouchEvent()) {
if (onTouchEvent(motionEvent)) {
- return TvIAppManager.Session.DISPATCH_HANDLED;
+ return TvInteractiveAppManager.Session.DISPATCH_HANDLED;
}
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
if (onTrackballEvent(motionEvent)) {
- return TvIAppManager.Session.DISPATCH_HANDLED;
+ return TvInteractiveAppManager.Session.DISPATCH_HANDLED;
}
} else {
if (onGenericMotionEvent(motionEvent)) {
- return TvIAppManager.Session.DISPATCH_HANDLED;
+ return TvInteractiveAppManager.Session.DISPATCH_HANDLED;
}
}
}
// TODO: handle overlay view
- return TvIAppManager.Session.DISPATCH_NOT_HANDLED;
+ return TvInteractiveAppManager.Session.DISPATCH_NOT_HANDLED;
}
private void initialize(ITvInteractiveAppSessionCallback callback) {
@@ -1443,9 +1472,9 @@
}
int handled = mSessionImpl.dispatchInputEvent(event, this);
- if (handled != TvIAppManager.Session.DISPATCH_IN_PROGRESS) {
+ if (handled != TvInteractiveAppManager.Session.DISPATCH_IN_PROGRESS) {
finishInputEvent(
- event, handled == TvIAppManager.Session.DISPATCH_HANDLED);
+ event, handled == TvInteractiveAppManager.Session.DISPATCH_HANDLED);
}
}
}
@@ -1457,11 +1486,11 @@
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_NOTIFY_RTE_STATE_CHANGED = 3;
- private void broadcastRteStateChanged(int type, int state) {
+ private void broadcastRteStateChanged(int type, int state, int error) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).onStateChanged(type, state);
+ mCallbacks.getBroadcastItem(i).onStateChanged(type, state, error);
} catch (RemoteException e) {
Log.e(TAG, "error in broadcastRteStateChanged", e);
}
@@ -1491,7 +1520,7 @@
return;
}
ITvInteractiveAppSession stub = new ITvInteractiveAppSessionWrapper(
- android.media.tv.interactive.TvIAppService.this, sessionImpl, channel);
+ TvInteractiveAppService.this, sessionImpl, channel);
SomeArgs someArgs = SomeArgs.obtain();
someArgs.arg1 = sessionImpl;
@@ -1519,9 +1548,11 @@
return;
}
case DO_NOTIFY_RTE_STATE_CHANGED: {
- int type = msg.arg1;
- int state = msg.arg2;
- broadcastRteStateChanged(type, state);
+ SomeArgs args = (SomeArgs) msg.obj;
+ int type = (int) args.arg1;
+ int state = (int) args.arg2;
+ int error = (int) args.arg3;
+ broadcastRteStateChanged(type, state, error);
return;
}
default: {
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 6f99d51..9590d5d 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -27,9 +27,9 @@
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
import android.media.tv.TvView;
-import android.media.tv.interactive.TvIAppManager.Session;
-import android.media.tv.interactive.TvIAppManager.Session.FinishedInputEventCallback;
-import android.media.tv.interactive.TvIAppManager.SessionCallback;
+import android.media.tv.interactive.TvInteractiveAppManager.Session;
+import android.media.tv.interactive.TvInteractiveAppManager.Session.FinishedInputEventCallback;
+import android.media.tv.interactive.TvInteractiveAppManager.SessionCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -50,7 +50,6 @@
/**
* Displays contents of interactive TV applications.
- * @hide
*/
public class TvInteractiveAppView extends ViewGroup {
private static final String TAG = "TvInteractiveAppView";
@@ -61,7 +60,7 @@
private static final int UNSET_TVVIEW_SUCCESS = 3;
private static final int UNSET_TVVIEW_FAIL = 4;
- private final TvIAppManager mTvInteractiveAppManager;
+ private final TvInteractiveAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
private final Object mCallbackLock = new Object();
private Session mSession;
@@ -141,8 +140,8 @@
}
mDefStyleAttr = defStyleAttr;
resetSurfaceView();
- mTvInteractiveAppManager = (TvIAppManager) getContext().getSystemService(
- Context.TV_IAPP_SERVICE);
+ mTvInteractiveAppManager = (TvInteractiveAppManager) getContext().getSystemService(
+ Context.TV_INTERACTIVE_APP_SERVICE);
}
/**
@@ -152,8 +151,8 @@
* callback.
*/
public void setCallback(
- @NonNull TvInteractiveAppCallback callback,
- @NonNull @CallbackExecutor Executor executor) {
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull TvInteractiveAppCallback callback) {
synchronized (mCallbackLock) {
mCallbackExecutor = executor;
mCallback = callback;
@@ -381,9 +380,16 @@
/**
* Prepares the interactive application.
+ *
+ * @param iAppServiceId the interactive app service ID, which can be found in
+ * {@link TvInteractiveAppInfo#getId()}.
+ *
+ * @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList()
* @hide
*/
- public void prepareInteractiveApp(@NonNull String iAppServiceId, int type) {
+ public void prepareInteractiveApp(
+ @NonNull String iAppServiceId,
+ @TvInteractiveAppInfo.InteractiveAppType int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareInteractiveApp");
@@ -552,10 +558,10 @@
/**
* Sets the TvInteractiveAppView to receive events from TIS. This method links the session of
- * TvIAppManager to TvInputManager session, so the TIAS can get the TIS events.
+ * TvInteractiveAppManager to TvInputManager session, so the TIAS can get the TIS events.
*
* @param tvView the TvView to be linked to this TvInteractiveAppView via linking of Sessions.
- * @return to be added
+ * @return The result of the operation.
* @hide
*/
public int setTvView(@Nullable TvView tvView) {
@@ -583,6 +589,7 @@
/**
* To toggle Digital Teletext Application if there is one in AIT app list.
* @param enable
+ * @hide
*/
public void setTeletextAppEnabled(boolean enable) {
if (DEBUG) {
@@ -609,7 +616,7 @@
*/
public void onCommandRequest(
@NonNull String iAppServiceId,
- @NonNull @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ @NonNull @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
@Nullable Bundle parameters) {
}
@@ -617,10 +624,16 @@
* This is called when the session state is changed.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
- * @param state current session state.
+ * @param state the current state.
+ * @param err the error code for error state. {@link TvInteractiveAppManager#ERROR_NONE}
+ * is used when the state is not
+ * {@link TvInteractiveAppManager#INTERACTIVE_APP_STATE_ERROR}.
* @hide
*/
- public void onSessionStateChanged(@NonNull String iAppServiceId, int state) {
+ public void onStateChanged(
+ @NonNull String iAppServiceId,
+ @TvInteractiveAppManager.InteractiveAppState int state,
+ @TvInteractiveAppManager.ErrorCode int err) {
}
/**
@@ -642,13 +655,15 @@
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param state digital teletext app current state.
+ * @hide
*/
public void onTeletextAppStateChanged(
- @NonNull String iAppServiceId, @TvIAppManager.TeletextAppState int state) {
+ @NonNull String iAppServiceId,
+ @TvInteractiveAppManager.TeletextAppState int state) {
}
/**
- * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+ * This is called when {@link TvInteractiveAppService.Session#SetVideoBounds} is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
@@ -657,7 +672,7 @@
}
/**
- * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelUri} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
@@ -667,7 +682,7 @@
}
/**
- * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelLcn} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
@@ -677,7 +692,7 @@
}
/**
- * This is called when {@link TvIAppService.Session#RequestStreamVolume} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestStreamVolume} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
@@ -687,7 +702,7 @@
}
/**
- * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is
+ * This is called when {@link TvInteractiveAppService.Session#RequestTrackInfoList} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
@@ -700,6 +715,7 @@
* This is called when {@link TvIAppService.Session#RequestCurrentTvInputId} is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @hide
*/
public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
}
@@ -801,7 +817,7 @@
@Override
public void onCommandRequest(
Session session,
- @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
if (DEBUG) {
Log.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters="
@@ -825,9 +841,12 @@
}
@Override
- public void onSessionStateChanged(Session session, int state) {
+ public void onSessionStateChanged(
+ Session session,
+ @TvInteractiveAppManager.InteractiveAppState int state,
+ @TvInteractiveAppManager.ErrorCode int err) {
if (DEBUG) {
- Log.d(TAG, "onSessionStateChanged (state=" + state + ")");
+ Log.d(TAG, "onSessionStateChanged (state=" + state + "; err=" + err + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onSessionStateChanged - session not created");
@@ -838,7 +857,7 @@
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
- mCallback.onSessionStateChanged(mIAppServiceId, state);
+ mCallback.onStateChanged(mIAppServiceId, state, err);
}
}
});
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 9c4a83a..3157375 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -1002,7 +1002,7 @@
private native String nativeGetFrontendHardwareInfo();
private native int nativeSetMaxNumberOfFrontends(int frontendType, int maxNumber);
private native int nativeGetMaxNumberOfFrontends(int frontendType);
-
+ private native int nativeRemoveOutputPid(int pid);
private native Lnb nativeOpenLnbByHandle(int handle);
private native Lnb nativeOpenLnbByName(String name);
@@ -1565,6 +1565,36 @@
}
/**
+ * Filter out unnecessary PID (packet identifier) from frontend output.
+ *
+ * <p>It is used by the client to remove some video or audio PIDs of other program to reduce the
+ * total amount of recorded TS.
+ *
+ * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ *
+ * @return result status of the operation. Unsupported version or if current active frontend
+ * doesn’t support PID filtering out would return {@link #RESULT_UNAVAILABLE}.
+ * @throws IllegalStateException if there is no active frontend currently.
+ */
+ @Result
+ public int removeOutputPid(@IntRange(from = 0) int pid) {
+ mFrontendLock.lock();
+ try {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "Remove output PID")) {
+ return RESULT_UNAVAILABLE;
+ }
+ if (mFrontend == null) {
+ throw new IllegalStateException("frontend is not initialized");
+ }
+ return nativeRemoveOutputPid(pid);
+ } finally {
+ mFrontendLock.unlock();
+ }
+ }
+
+ /**
* Gets the currently initialized and activated frontend information. To get all the available
* frontend info on the device, use {@link getAvailableFrontendInfos()}.
*
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 0a5490d..2e419a6 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -375,7 +375,8 @@
}
static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobject jsurface,
- jint maxImages, jint userFormat, jint userWidth, jint userHeight) {
+ jint maxImages, jint userWidth, jint userHeight, jboolean useSurfaceImageFormatInfo,
+ jint hardwareBufferFormat, jlong dataSpace, jlong ndkUsage) {
status_t res;
ALOGV("%s: maxImages:%d", __FUNCTION__, maxImages);
@@ -450,7 +451,7 @@
// Query surface format if no valid user format is specified, otherwise, override surface format
// with user format.
- if (userFormat == IMAGE_FORMAT_UNKNOWN) {
+ if (useSurfaceImageFormatInfo) {
if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &surfaceFormat)) != OK) {
ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
jniThrowRuntimeException(env, "Failed to query Surface format");
@@ -458,13 +459,13 @@
}
} else {
// Set consumer buffer format to user specified format
- PublicFormat publicFormat = static_cast<PublicFormat>(userFormat);
- int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
- android_dataspace nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
- res = native_window_set_buffers_format(anw.get(), nativeFormat);
+ android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
+ int userFormat = static_cast<int>(mapHalFormatDataspaceToPublicFormat(
+ hardwareBufferFormat, nativeDataspace));
+ res = native_window_set_buffers_format(anw.get(), hardwareBufferFormat);
if (res != OK) {
ALOGE("%s: Unable to configure consumer native buffer format to %#x",
- __FUNCTION__, nativeFormat);
+ __FUNCTION__, hardwareBufferFormat);
jniThrowRuntimeException(env, "Failed to set Surface format");
return 0;
}
@@ -484,15 +485,13 @@
env->SetIntField(thiz,
gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
- if (!isFormatOpaque(surfaceFormat)) {
- res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (res != OK) {
- ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
- __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
- surfaceFormat, strerror(-res), res);
- jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
- return 0;
- }
+ res = native_window_set_usage(anw.get(), ndkUsage);
+ if (res != OK) {
+ ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
+ __FUNCTION__, static_cast<unsigned int>(ndkUsage),
+ surfaceFormat, strerror(-res), res);
+ jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
+ return 0;
}
int minUndequeuedBufferCount = 0;
@@ -1093,7 +1092,7 @@
static JNINativeMethod gImageWriterMethods[] = {
{"nativeClassInit", "()V", (void*)ImageWriter_classInit },
- {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;IIII)J",
+ {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;IIIZIJJ)J",
(void*)ImageWriter_init },
{"nativeClose", "(J)V", (void*)ImageWriter_close },
{"nativeAttachAndQueueImage",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e6a79796..41f3a678 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1622,6 +1622,15 @@
return mTunerClient->getMaxNumberOfFrontends(static_cast<FrontendType>(type));
}
+jint JTuner::removeOutputPid(int32_t pid) {
+ if (mFeClient == nullptr) {
+ ALOGE("frontend is not initialized");
+ return (jint)Result::INVALID_STATE;
+ }
+
+ return (jint)mFeClient->removeOutputPid(pid);
+}
+
jobject JTuner::openLnbByHandle(int handle) {
if (mTunerClient == nullptr) {
return nullptr;
@@ -4375,6 +4384,11 @@
return tuner->getMaxNumberOfFrontends(type);
}
+static jint android_media_tv_Tuner_remove_output_pid(JNIEnv *env, jobject thiz, jint pid) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->removeOutputPid(pid);
+}
+
static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->closeFrontend();
@@ -4694,6 +4708,8 @@
(void *)android_media_tv_Tuner_set_maximum_frontends },
{ "nativeGetMaxNumberOfFrontends", "(I)I",
(void *)android_media_tv_Tuner_get_maximum_frontends },
+ { "nativeRemoveOutputPid", "(I)I",
+ (void *)android_media_tv_Tuner_remove_output_pid },
};
static const JNINativeMethod gFilterMethods[] = {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 502bd6b..e9475dc 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -205,6 +205,7 @@
Result getFrontendHardwareInfo(string& info);
jint setMaxNumberOfFrontends(int32_t frontendType, int32_t maxNumber);
int32_t getMaxNumberOfFrontends(int32_t frontendType);
+ jint removeOutputPid(int32_t pid);
jweak getObject();
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index 0fdd8d8..bea0342 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -143,6 +143,15 @@
return Result::INVALID_STATE;
}
+Result FrontendClient::removeOutputPid(int32_t pid) {
+ if (mTunerFrontend != nullptr) {
+ Status s = mTunerFrontend->removeOutputPid(pid);
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
+
+ return Result::INVALID_STATE;
+}
+
shared_ptr<ITunerFrontend> FrontendClient::getAidlFrontend() {
return mTunerFrontend;
}
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 77d9098..c6838c8 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -120,6 +120,11 @@
*/
Result getHardwareInfo(string& info);
+ /**
+ * Filter out unnecessary PID from frontend output.
+ */
+ Result removeOutputPid(int32_t pid);
+
int32_t getId();
shared_ptr<ITunerFrontend> getAidlFrontend();
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index 2dd9525..4c3b689 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -24,6 +24,7 @@
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDeviceStatus;
@@ -63,6 +64,7 @@
"00002902-0000-1000-8000-00805f9b34fb");
private final BluetoothDevice mBluetoothDevice;
+ private final Context mContext;
private final BluetoothMidiService mService;
private final MidiManager mMidiManager;
private MidiReceiver mOutputReceiver;
@@ -136,6 +138,8 @@
// switch to receiving notifications
mBluetoothGatt.readCharacteristic(characteristic);
}
+
+ openBluetoothDevice(mBluetoothDevice);
}
} else {
Log.e(TAG, "onServicesDiscovered received: " + status);
@@ -249,6 +253,7 @@
mBluetoothGatt = mBluetoothDevice.connectGatt(context, false, mGattCallback);
+ mContext = context;
mMidiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
Bundle properties = new Bundle();
@@ -310,6 +315,18 @@
}
}
+ void openBluetoothDevice(BluetoothDevice btDevice) {
+ Log.d(TAG, "openBluetoothDevice() device: " + btDevice);
+
+ MidiManager midiManager = mContext.getSystemService(MidiManager.class);
+ midiManager.openBluetoothDevice(btDevice,
+ new MidiManager.OnDeviceOpenedListener() {
+ @Override
+ public void onDeviceOpened(MidiDevice device) {
+ }
+ }, null);
+ }
+
public IBinder getBinder() {
return mDeviceServer.asBinder();
}
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index 45253bb..b150e01 100644
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -28,4 +28,9 @@
<!-- Control whether status bar should distinguish HSPA data icon form UMTS
data icon on devices -->
<bool name="config_hspa_data_distinguishable">false</bool>
+
+ <integer-array name="config_supportedDreamComplications">
+ </integer-array>
+ <integer-array name="config_dreamComplicationsEnabledByDefault">
+ </integer-array>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index 5f2bef7..64a0781 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -31,9 +31,8 @@
private int mLastDensity;
public InterestingConfigChanges() {
- this(ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ASSETS_PATHS);
+ this(ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_LAYOUT_DIRECTION
+ | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_ASSETS_PATHS);
}
public InterestingConfigChanges(int flags) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index aed2ec1..3c444f2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -38,6 +38,8 @@
import android.util.Log;
import android.util.Xml;
+import com.android.settingslib.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,9 +47,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
public class DreamBackend {
private static final String TAG = "DreamBackend";
@@ -78,19 +83,41 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef({WHILE_CHARGING, WHILE_DOCKED, EITHER, NEVER})
- public @interface WhenToDream{}
+ public @interface WhenToDream {}
public static final int WHILE_CHARGING = 0;
public static final int WHILE_DOCKED = 1;
public static final int EITHER = 2;
public static final int NEVER = 3;
+ /**
+ * The type of dream complications which can be provided by a
+ * {@link com.android.systemui.dreams.ComplicationProvider}.
+ */
+ @IntDef(prefix = {"COMPLICATION_TYPE_"}, value = {
+ COMPLICATION_TYPE_TIME,
+ COMPLICATION_TYPE_DATE,
+ COMPLICATION_TYPE_WEATHER,
+ COMPLICATION_TYPE_AIR_QUALITY,
+ COMPLICATION_TYPE_CAST_INFO
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComplicationType {}
+
+ public static final int COMPLICATION_TYPE_TIME = 1;
+ public static final int COMPLICATION_TYPE_DATE = 2;
+ public static final int COMPLICATION_TYPE_WEATHER = 3;
+ public static final int COMPLICATION_TYPE_AIR_QUALITY = 4;
+ public static final int COMPLICATION_TYPE_CAST_INFO = 5;
+
private final Context mContext;
private final IDreamManager mDreamManager;
private final DreamInfoComparator mComparator;
private final boolean mDreamsEnabledByDefault;
private final boolean mDreamsActivatedOnSleepByDefault;
private final boolean mDreamsActivatedOnDockByDefault;
+ private final Set<Integer> mSupportedComplications;
+ private final Set<Integer> mDefaultEnabledComplications;
private static DreamBackend sInstance;
@@ -103,17 +130,31 @@
public DreamBackend(Context context) {
mContext = context.getApplicationContext();
+ final Resources resources = mContext.getResources();
+
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
mComparator = new DreamInfoComparator(getDefaultDream());
- mDreamsEnabledByDefault = mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault);
- mDreamsActivatedOnSleepByDefault = mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
- mDreamsActivatedOnDockByDefault = mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
- mDreamPreviewDefault = mContext.getResources().getDrawable(
+ mDreamsEnabledByDefault = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledByDefault);
+ mDreamsActivatedOnSleepByDefault = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
+ mDreamsActivatedOnDockByDefault = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamPreviewDefault = resources.getDrawable(
com.android.internal.R.drawable.default_dream_preview);
+
+ mSupportedComplications =
+ Arrays.stream(resources.getIntArray(R.array.config_supportedDreamComplications))
+ .boxed()
+ .collect(Collectors.toSet());
+
+ mDefaultEnabledComplications = Arrays.stream(
+ resources.getIntArray(R.array.config_dreamComplicationsEnabledByDefault))
+ .boxed()
+ // A complication can only be enabled by default if it is also supported.
+ .filter(mSupportedComplications::contains)
+ .collect(Collectors.toSet());
}
public List<DreamInfo> getDreamInfos() {
@@ -242,7 +283,57 @@
default:
break;
}
+ }
+ /** Gets all complications which have been enabled by the user. */
+ public Set<Integer> getEnabledComplications() {
+ final String enabledComplications = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS);
+
+ if (enabledComplications == null) {
+ return mDefaultEnabledComplications;
+ }
+
+ return parseFromString(enabledComplications);
+ }
+
+ /** Gets all dream complications which are supported on this device. **/
+ public Set<Integer> getSupportedComplications() {
+ return mSupportedComplications;
+ }
+
+ /**
+ * Enables or disables a particular dream complication.
+ *
+ * @param complicationType The dream complication to be enabled/disabled.
+ * @param value If true, the complication is enabled. Otherwise it is disabled.
+ */
+ public void setComplicationEnabled(@ComplicationType int complicationType, boolean value) {
+ if (!mSupportedComplications.contains(complicationType)) return;
+
+ Set<Integer> enabledComplications = getEnabledComplications();
+ if (value) {
+ enabledComplications.add(complicationType);
+ } else {
+ enabledComplications.remove(complicationType);
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS,
+ convertToString(enabledComplications));
+ }
+
+ private static String convertToString(Set<Integer> set) {
+ return set.stream()
+ .map(String::valueOf)
+ .collect(Collectors.joining(","));
+ }
+
+ private static Set<Integer> parseFromString(String string) {
+ return Arrays.stream(string.split(","))
+ .map(Integer::parseInt)
+ .collect(Collectors.toSet());
}
public boolean isEnabled() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
new file mode 100644
index 0000000..53d4653
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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.settingslib.dream;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import com.android.settingslib.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSettings;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSettings.ShadowSecure.class})
+public final class DreamBackendTest {
+ private static final int[] SUPPORTED_DREAM_COMPLICATIONS = {1, 2, 3};
+ private static final int[] DEFAULT_DREAM_COMPLICATIONS = {1, 3, 4};
+
+ @Mock
+ private Context mContext;
+ private DreamBackend mBackend;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+
+ final Resources res = mock(Resources.class);
+ when(mContext.getResources()).thenReturn(res);
+ when(res.getIntArray(R.array.config_supportedDreamComplications)).thenReturn(
+ SUPPORTED_DREAM_COMPLICATIONS);
+ when(res.getIntArray(R.array.config_dreamComplicationsEnabledByDefault)).thenReturn(
+ DEFAULT_DREAM_COMPLICATIONS);
+ mBackend = new DreamBackend(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowSettings.ShadowSecure.reset();
+ }
+
+ @Test
+ public void testSupportedComplications() {
+ assertThat(mBackend.getSupportedComplications()).containsExactly(1, 2, 3);
+ }
+
+ @Test
+ public void testGetEnabledDreamComplications_default() {
+ assertThat(mBackend.getEnabledComplications()).containsExactly(1, 3);
+ }
+
+ @Test
+ public void testEnableComplication() {
+ mBackend.setComplicationEnabled(/* complicationType= */ 2, true);
+ assertThat(mBackend.getEnabledComplications()).containsExactly(1, 2, 3);
+ }
+
+ @Test
+ public void testEnableComplication_notSupported() {
+ mBackend.setComplicationEnabled(/* complicationType= */ 5, true);
+ assertThat(mBackend.getEnabledComplications()).containsExactly(1, 3);
+ }
+
+ @Test
+ public void testDisableComplication() {
+ mBackend.setComplicationEnabled(/* complicationType= */ 1, false);
+ assertThat(mBackend.getEnabledComplications()).containsExactly(3);
+ }
+}
+
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
index aa11952..06b6fc8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
@@ -22,7 +22,6 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -37,7 +36,6 @@
import com.android.settingslib.RestrictedLockUtils;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -67,9 +65,8 @@
}
@Test
- @Ignore
public void buttonClicked() {
- ComponentName componentName = mock(ComponentName.class);
+ ComponentName componentName = new ComponentName("com.android.test", "AThing");
RestrictedLockUtils.EnforcedAdmin enforcedAdmin = new RestrictedLockUtils.EnforcedAdmin(
componentName, new UserHandle(UserHandle.myUserId()));
@@ -85,6 +82,6 @@
assertEquals(Settings.SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS,
intentCaptor.getValue().getStringExtra(
Settings.EXTRA_SUPERVISOR_RESTRICTED_SETTING_KEY));
- assertSame(componentName, intentCaptor.getValue().getComponent());
+ assertEquals(componentName.getPackageName(), intentCaptor.getValue().getPackage());
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index c5f027b..7381e05 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1378,9 +1378,6 @@
Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE,
GlobalSettingsProto.Sys.STORAGE_CACHE_PERCENTAGE);
dumpSetting(s, p,
- Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
- GlobalSettingsProto.Sys.STORAGE_CACHE_MAX_BYTES);
- dumpSetting(s, p,
Settings.Global.SYS_UIDCPUPOWER,
GlobalSettingsProto.Sys.UIDCPUPOWER);
p.end(sysToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index a3f3995..720fb6c 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -462,7 +462,6 @@
Settings.Global.SYNC_MANAGER_CONSTANTS,
Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
- Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE,
Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0bf3648..46e24fa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -549,6 +549,10 @@
<!-- Permission required for CTS test - PeopleManagerTest -->
<uses-permission android:name="android.permission.READ_PEOPLE_DATA" />
+ <!-- Permissions required for CTS test - TrustTestCases -->
+ <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+
<!-- Permission required for CTS test - CtsGameManagerTestCases -->
<uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index 1d2caf9..6345d11 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -275,23 +275,27 @@
}
public void dump(PrintWriter pw) {
- pw.println("RegionSamplingHelper:");
- pw.println(" sampleView isAttached: " + mSampledView.isAttachedToWindow());
- pw.println(" sampleView isScValid: " + (mSampledView.isAttachedToWindow()
+ dump("", pw);
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "RegionSamplingHelper:");
+ pw.println(prefix + "\tsampleView isAttached: " + mSampledView.isAttachedToWindow());
+ pw.println(prefix + "\tsampleView isScValid: " + (mSampledView.isAttachedToWindow()
? mSampledView.getViewRootImpl().getSurfaceControl().isValid()
: "notAttached"));
- pw.println(" mSamplingEnabled: " + mSamplingEnabled);
- pw.println(" mSamplingListenerRegistered: " + mSamplingListenerRegistered);
- pw.println(" mSamplingRequestBounds: " + mSamplingRequestBounds);
- pw.println(" mRegisteredSamplingBounds: " + mRegisteredSamplingBounds);
- pw.println(" mLastMedianLuma: " + mLastMedianLuma);
- pw.println(" mCurrentMedianLuma: " + mCurrentMedianLuma);
- pw.println(" mWindowVisible: " + mWindowVisible);
- pw.println(" mWindowHasBlurs: " + mWindowHasBlurs);
- pw.println(" mWaitingOnDraw: " + mWaitingOnDraw);
- pw.println(" mRegisteredStopLayer: " + mRegisteredStopLayer);
- pw.println(" mWrappedStopLayer: " + mWrappedStopLayer);
- pw.println(" mIsDestroyed: " + mIsDestroyed);
+ pw.println(prefix + "\tmSamplingEnabled: " + mSamplingEnabled);
+ pw.println(prefix + "\tmSamplingListenerRegistered: " + mSamplingListenerRegistered);
+ pw.println(prefix + "\tmSamplingRequestBounds: " + mSamplingRequestBounds);
+ pw.println(prefix + "\tmRegisteredSamplingBounds: " + mRegisteredSamplingBounds);
+ pw.println(prefix + "\tmLastMedianLuma: " + mLastMedianLuma);
+ pw.println(prefix + "\tmCurrentMedianLuma: " + mCurrentMedianLuma);
+ pw.println(prefix + "\tmWindowVisible: " + mWindowVisible);
+ pw.println(prefix + "\tmWindowHasBlurs: " + mWindowHasBlurs);
+ pw.println(prefix + "\tmWaitingOnDraw: " + mWaitingOnDraw);
+ pw.println(prefix + "\tmRegisteredStopLayer: " + mRegisteredStopLayer);
+ pw.println(prefix + "\tmWrappedStopLayer: " + mWrappedStopLayer);
+ pw.println(prefix + "\tmIsDestroyed: " + mIsDestroyed);
}
public interface SamplingCallback {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index d518cb5..bb7a0a71 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -52,13 +52,14 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.view.RotationPolicy;
-import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.utilities.ViewRippler;
+import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.io.PrintWriter;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -450,6 +451,30 @@
return mDarkIconColor;
}
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "RotationButtonController:");
+
+ pw.println(String.format(
+ "%s\tmIsRecentsAnimationRunning=%b", prefix, mIsRecentsAnimationRunning));
+ pw.println(String.format("%s\tmHomeRotationEnabled=%b", prefix, mHomeRotationEnabled));
+ pw.println(String.format(
+ "%s\tmLastRotationSuggestion=%d", prefix, mLastRotationSuggestion));
+ pw.println(String.format(
+ "%s\tmPendingRotationSuggestion=%b", prefix, mPendingRotationSuggestion));
+ pw.println(String.format(
+ "%s\tmHoveringRotationSuggestion=%b", prefix, mHoveringRotationSuggestion));
+ pw.println(String.format("%s\tmListenersRegistered=%b", prefix, mListenersRegistered));
+ pw.println(String.format(
+ "%s\tmIsNavigationBarShowing=%b", prefix, mIsNavigationBarShowing));
+ pw.println(String.format("%s\tmBehavior=%d", prefix, mBehavior));
+ pw.println(String.format(
+ "%s\tmSkipOverrideUserLockPrefsOnce=%b", prefix, mSkipOverrideUserLockPrefsOnce));
+ pw.println(String.format(
+ "%s\tmLightIconColor=0x%s", prefix, Integer.toHexString(mLightIconColor)));
+ pw.println(String.format(
+ "%s\tmDarkIconColor=0x%s", prefix, Integer.toHexString(mDarkIconColor)));
+ }
+
public RotationButton getRotationButton() {
return mRotationButton;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
index 0340904..b2658c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import android.util.Log;
+
/**
* Defines constants for the Keyguard.
*/
@@ -25,7 +27,7 @@
* Turns on debugging information for the whole Keyguard. This is very verbose and should only
* be used temporarily for debugging.
*/
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
public static final boolean DEBUG_SIM_STATES = true;
public static final boolean DEBUG_BIOMETRIC_WAKELOCK = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 2767904..b3be877 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -122,7 +122,8 @@
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
.setCompatUI(Optional.of(mWMComponent.getCompatUI()))
- .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
+ .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()))
+ .setBackAnimation(mWMComponent.getBackAnimation());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
// is separating this logic into newly creating SystemUITestsFactory.
@@ -142,7 +143,8 @@
.setTaskSurfaceHelper(Optional.ofNullable(null))
.setRecentTasks(Optional.ofNullable(null))
.setCompatUI(Optional.ofNullable(null))
- .setDragAndDrop(Optional.ofNullable(null));
+ .setDragAndDrop(Optional.ofNullable(null))
+ .setBackAnimation(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index b235692..bda8e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
@@ -121,6 +122,9 @@
@BindsInstance
Builder setDragAndDrop(Optional<DragAndDrop> d);
+ @BindsInstance
+ Builder setBackAnimation(Optional<BackAnimation> b);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index b815d4e..b926692 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -24,6 +24,7 @@
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.dagger.TvWMShellModule;
@@ -123,4 +124,7 @@
@WMSingleton
DragAndDrop getDragAndDrop();
+
+ @WMSingleton
+ Optional<BackAnimation> getBackAnimation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index b24d08d..3ae11ff 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -54,7 +54,7 @@
private final View mRootView;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
+ | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_ASSETS_PATHS);
private final FragmentService mManager;
private final ExtensionFragmentManager mPlugins = new ExtensionFragmentManager();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index d190dcb..1bef32a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -141,6 +141,7 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
@@ -190,6 +191,7 @@
private final Optional<Pip> mPipOptional;
private final Optional<LegacySplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
+ private final Optional<BackAnimation> mBackAnimation;
private final SystemActions mSystemActions;
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
@@ -504,7 +506,8 @@
AutoHideController mainAutoHideController,
AutoHideController.Factory autoHideControllerFactory,
Optional<TelecomManager> telecomManagerOptional,
- InputMethodManager inputMethodManager) {
+ InputMethodManager inputMethodManager,
+ Optional<BackAnimation> backAnimation) {
mContext = context;
mWindowManager = windowManager;
mAccessibilityManager = accessibilityManager;
@@ -524,6 +527,7 @@
mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
+ mBackAnimation = backAnimation;
mSystemActions = systemActions;
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
@@ -629,6 +633,7 @@
mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
mPipOptional.ifPresent(mNavigationBarView::addPipExclusionBoundsChangeListener);
+ mBackAnimation.ifPresent(mNavigationBarView::registerBackAnimation);
prepareNavigationBarView();
checkNavBarModes();
@@ -1680,6 +1685,7 @@
private final AutoHideController.Factory mAutoHideControllerFactory;
private final Optional<TelecomManager> mTelecomManagerOptional;
private final InputMethodManager mInputMethodManager;
+ private final Optional<BackAnimation> mBackAnimation;
@Inject
public Factory(
@@ -1712,7 +1718,8 @@
AutoHideController mainAutoHideController,
AutoHideController.Factory autoHideControllerFactory,
Optional<TelecomManager> telecomManagerOptional,
- InputMethodManager inputMethodManager) {
+ InputMethodManager inputMethodManager,
+ Optional<BackAnimation> backAnimation) {
mAssistManagerLazy = assistManagerLazy;
mAccessibilityManager = accessibilityManager;
mDeviceProvisionedController = deviceProvisionedController;
@@ -1743,6 +1750,7 @@
mAutoHideControllerFactory = autoHideControllerFactory;
mTelecomManagerOptional = telecomManagerOptional;
mInputMethodManager = inputMethodManager;
+ mBackAnimation = backAnimation;
}
/** Construct a {@link NavigationBar} */
@@ -1759,7 +1767,7 @@
mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
mUserTracker, mMainLightBarController, mLightBarControllerFactory,
mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
- mInputMethodManager);
+ mInputMethodManager, mBackAnimation);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index a984974..98b49b1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -59,6 +59,7 @@
import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
import java.io.FileDescriptor;
@@ -109,7 +110,8 @@
DumpManager dumpManager,
AutoHideController autoHideController,
LightBarController lightBarController,
- Optional<Pip> pipOptional) {
+ Optional<Pip> pipOptional,
+ Optional<BackAnimation> backAnimation) {
mContext = context;
mHandler = mainHandler;
mNavigationBarFactory = navigationBarFactory;
@@ -121,7 +123,8 @@
mTaskbarDelegate = taskbarDelegate;
mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
navBarHelper, navigationModeController, sysUiFlagsContainer,
- dumpManager, autoHideController, lightBarController, pipOptional);
+ dumpManager, autoHideController, lightBarController, pipOptional,
+ backAnimation.orElse(null));
mIsTablet = isTablet(mContext);
dumpManager.registerDumpable(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index ac816ba..2dd89f3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -91,6 +91,7 @@
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
@@ -1417,6 +1418,10 @@
pip.removePipExclusionBoundsChangeListener(mPipListener);
}
+ void registerBackAnimation(BackAnimation backAnimation) {
+ mEdgeBackGestureHandler.setBackAnimation(backAnimation);
+ }
+
private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
pw.print(" " + caption + ": ");
if (button == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 002dd10..441e79a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -69,6 +69,7 @@
import com.android.systemui.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
import java.io.FileDescriptor;
@@ -150,6 +151,7 @@
mAutoHideController.touchAutoHide();
}
};
+ private BackAnimation mBackAnimation;
@Inject
public TaskbarDelegate(Context context) {
@@ -172,7 +174,8 @@
SysUiState sysUiState, DumpManager dumpManager,
AutoHideController autoHideController,
LightBarController lightBarController,
- Optional<Pip> pipOptional) {
+ Optional<Pip> pipOptional,
+ BackAnimation backAnimation) {
// TODO: adding this in the ctor results in a dagger dependency cycle :(
mCommandQueue = commandQueue;
mOverviewProxyService = overviewProxyService;
@@ -184,6 +187,7 @@
mLightBarController = lightBarController;
mLightBarTransitionsController = createLightBarTransitionsController();
mPipOptional = pipOptional;
+ mBackAnimation = backAnimation;
}
// Separated into a method to keep setDependencies() clean/readable.
@@ -233,6 +237,7 @@
mAutoHideController.setNavigationBar(mAutoHideUiElement);
mLightBarController.setNavigationBar(mLightBarTransitionsController);
mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener);
+ mEdgeBackGestureHandler.setBackAnimation(mBackAnimation);
mInitialized = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index ab48a28..9e350ee 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -79,6 +79,7 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
+import com.android.wm.shell.back.BackAnimation;
import java.io.PrintWriter;
import java.util.ArrayDeque;
@@ -231,6 +232,7 @@
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
private NavigationEdgeBackPlugin mEdgeBackPlugin;
+ private BackAnimation mBackAnimation;
private int mLeftInset;
private int mRightInset;
private int mSysUiFlags;
@@ -494,7 +496,7 @@
Choreographer.getInstance(), this::onInputEvent);
// Add a nav bar panel window
- setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
+ setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
}
@@ -509,7 +511,7 @@
@Override
public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
- setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
+ setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
}
private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
@@ -930,6 +932,10 @@
proto.edgeBackGestureHandler.allowGesture = mAllowGesture;
}
+ public void setBackAnimation(BackAnimation backAnimation) {
+ mBackAnimation = backAnimation;
+ }
+
/**
* Injectable instance to create a new EdgeBackGestureHandler.
*
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 8d1dfc8..c18209d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -57,6 +57,7 @@
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.wm.shell.back.BackAnimation;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -277,11 +278,14 @@
}
};
private BackCallback mBackCallback;
+ private final BackAnimation mBackAnimation;
- public NavigationBarEdgePanel(Context context) {
+ public NavigationBarEdgePanel(Context context,
+ BackAnimation backAnimation) {
super(context);
mWindowManager = context.getSystemService(WindowManager.class);
+ mBackAnimation = backAnimation;
mVibratorHelper = Dependency.get(VibratorHelper.class);
mDensity = context.getResources().getDisplayMetrics().density;
@@ -459,6 +463,9 @@
@Override
public void onMotionEvent(MotionEvent event) {
+ if (mBackAnimation != null) {
+ mBackAnimation.onBackMotion(event);
+ }
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -866,6 +873,9 @@
// Whenever the trigger back state changes the existing translation animation should be
// cancelled
mTranslationAnimation.cancel();
+ if (mBackAnimation != null) {
+ mBackAnimation.setTriggerBack(triggerBack);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
new file mode 100644
index 0000000..03b978e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 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
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * A class which keeps track of whether section headers should be shown in the notification shade.
+ *
+ * (In an ideal world, this would directly monitor the state of the keyguard and invalidate the
+ * pipeline to show/hide headers, but the KeyguardController already invalidates the pipeline when
+ * the keyguard's state changes. Instead of having both classes monitor for state changes and ending
+ * up with duplicate runs of the pipeline, we let the KeyguardController update the header
+ * visibility when it invalidates, and we just store that state here.)
+ */
+@SysUISingleton
+class SectionHeaderVisibilityProvider @Inject constructor() {
+ var sectionHeadersVisible = true
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index 09ae7eb..87e531c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -260,7 +260,8 @@
}
events.sort(mEventComparator);
- mLogger.logEmitBatch(batch.mGroupKey);
+ long batchAge = mClock.uptimeMillis() - batch.mCreatedTimestamp;
+ mLogger.logEmitBatch(batch.mGroupKey, batch.mMembers.size(), batchAge);
mHandler.onNotificationBatchPosted(events);
}
@@ -337,6 +338,6 @@
void onNotificationBatchPosted(List<CoalescedEvent> events);
}
- private static final int MIN_GROUP_LINGER_DURATION = 50;
+ private static final int MIN_GROUP_LINGER_DURATION = 200;
private static final int MAX_GROUP_LINGER_DURATION = 500;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
index d4d5b64..211e374 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
@@ -32,11 +32,13 @@
})
}
- fun logEmitBatch(groupKey: String) {
+ fun logEmitBatch(groupKey: String, batchSize: Int, batchAgeMs: Long) {
buffer.log(TAG, LogLevel.DEBUG, {
str1 = groupKey
+ int1 = batchSize
+ long1 = batchAgeMs
}, {
- "Emitting event batch for group $str1"
+ "Emitting batch for group $str1 size=$int1 age=${long1}ms"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index e59f4a6..ba88ad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -20,11 +20,13 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.dagger.PeopleHeader
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import javax.inject.Inject
@@ -48,18 +50,36 @@
val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) {
override fun isInSection(entry: ListEntry): Boolean =
- isConversation(entry.representativeEntry!!)
+ isConversation(entry)
override fun getHeaderNodeController() =
// TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController
if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null
}
+ val comparator = object : NotifComparator("People") {
+ override fun compare(entry1: ListEntry, entry2: ListEntry): Int {
+ assert(entry1.section === entry2.section)
+ if (entry1.section?.sectioner !== sectioner) {
+ return 0
+ }
+ val type1 = getPeopleType(entry1)
+ val type2 = getPeopleType(entry2)
+ return type2.compareTo(type1)
+ }
+ }
+
override fun attach(pipeline: NotifPipeline) {
pipeline.addPromoter(notificationPromoter)
}
- private fun isConversation(entry: NotificationEntry): Boolean =
- peopleNotificationIdentifier.getPeopleNotificationType(entry) != TYPE_NON_PERSON
+ private fun isConversation(entry: ListEntry): Boolean =
+ getPeopleType(entry) != TYPE_NON_PERSON
+
+ @PeopleNotificationType
+ private fun getPeopleType(entry: ListEntry): Int =
+ entry.representativeEntry?.let {
+ peopleNotificationIdentifier.getPeopleNotificationType(it)
+ } ?: TYPE_NON_PERSON
companion object {
private const val TAG = "ConversationCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 33005b3..733be9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -36,6 +36,8 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -48,7 +50,8 @@
import javax.inject.Inject;
/**
- * Filters low priority and privacy-sensitive notifications from the lockscreen.
+ * Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
+ * headers on the lockscreen.
*/
@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
@@ -62,6 +65,7 @@
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final HighPriorityProvider mHighPriorityProvider;
+ private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
private boolean mHideSilentNotificationsOnLockscreen;
@@ -74,7 +78,8 @@
BroadcastDispatcher broadcastDispatcher,
StatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- HighPriorityProvider highPriorityProvider) {
+ HighPriorityProvider highPriorityProvider,
+ SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider) {
mContext = context;
mMainHandler = mainThreadHandler;
mKeyguardStateController = keyguardStateController;
@@ -83,6 +88,7 @@
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mHighPriorityProvider = highPriorityProvider;
+ mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
}
@Override
@@ -214,6 +220,8 @@
}
private void invalidateListFromFilter(String reason) {
+ mSectionHeaderVisibilityProvider.setSectionHeadersVisible(
+ mStatusBarStateController.getState() != StatusBarState.KEYGUARD);
mNotifFilter.invalidateList();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 757fb5a..850cb4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -20,6 +20,7 @@
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -63,6 +64,7 @@
private val mCoordinators: MutableList<Coordinator> = ArrayList()
private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
+ private val mOrderedComparators: MutableList<NotifComparator> = ArrayList()
/**
* Creates all the coordinators.
@@ -117,6 +119,9 @@
mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized
+
+ // Manually add ordered comparators
+ mOrderedComparators.add(conversationCoordinator.comparator)
}
/**
@@ -128,6 +133,7 @@
c.attach(pipeline)
}
pipeline.setSections(mOrderedSections)
+ pipeline.setComparators(mOrderedComparators)
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
index 0d150ed..f7bbd28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+import androidx.annotation.NonNull;
+
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -39,5 +41,5 @@
* @return a negative integer, zero, or a positive integer as the first argument is less than
* equal to, or greater than the second (same as standard Comparator<> interface).
*/
- public abstract int compare(ListEntry o1, ListEntry o2);
+ public abstract int compare(@NonNull ListEntry o1, @NonNull ListEntry o2);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index f13470e..607500e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.render
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -35,6 +36,7 @@
class NodeSpecBuilder(
private val mediaContainerController: MediaContainerController,
private val sectionsFeatureManager: NotificationSectionsFeatureManager,
+ private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
private val viewBarn: NotifViewBarn
) {
fun buildNodeSpec(
@@ -51,6 +53,7 @@
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
+ val showHeaders = sectionHeaderVisibilityProvider.sectionHeadersVisible
for (entry in notifList) {
val section = entry.section!!
@@ -61,7 +64,7 @@
// If this notif begins a new section, first add the section's header view
if (section != currentSection) {
- if (section.headerController != currentSection?.headerController) {
+ if (section.headerController != currentSection?.headerController && showHeaders) {
section.headerController?.let { headerController ->
root.children.add(NodeSpecImpl(root, headerController))
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index ad97392..4847072 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.view.View
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -38,13 +39,15 @@
@Assisted private val stackController: NotifStackController,
mediaContainerController: MediaContainerController,
featureManager: NotificationSectionsFeatureManager,
+ sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn
) {
// We pass a shim view here because the listContainer may not actually have a view associated
// with it and the differ never actually cares about the root node's view.
private val rootController = RootNodeController(listContainer, View(context))
- private val specBuilder = NodeSpecBuilder(mediaContainerController, featureManager, viewBarn)
+ private val specBuilder = NodeSpecBuilder(mediaContainerController, featureManager,
+ sectionHeaderVisibilityProvider, viewBarn)
private val viewDiffer = ShadeViewDiffer(rootController, logger)
/** Method for attaching this manager to the pipeline. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 5d6e807..aff73e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -349,6 +349,9 @@
}
private void updateShelfIcons() {
+ if (mShelfIcons == null) {
+ return;
+ }
updateIconsForLayout(entry -> entry.getIcons().getShelfIcon(), mShelfIcons,
true /* showAmbient */,
true /* showLowPriority */,
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 81e5b58..016b953 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -46,6 +46,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.StatusBarManager;
@@ -211,8 +212,10 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -4920,33 +4923,53 @@
private class DebugDrawable extends Drawable {
+ private final Set<Integer> mDebugTextUsedYPositions = new HashSet<>();
+ private final Paint mDebugPaint = new Paint();
+
@Override
- public void draw(Canvas canvas) {
- Paint p = new Paint();
- p.setColor(Color.RED);
- p.setStrokeWidth(2);
- p.setStyle(Paint.Style.STROKE);
- canvas.drawLine(0, getMaxPanelHeight(), mView.getWidth(), getMaxPanelHeight(), p);
- p.setTextSize(24);
- if (mHeaderDebugInfo != null) canvas.drawText(mHeaderDebugInfo, 50, 100, p);
- p.setColor(Color.BLUE);
- canvas.drawLine(0, getExpandedHeight(), mView.getWidth(), getExpandedHeight(), p);
- p.setColor(Color.GREEN);
- canvas.drawLine(0, calculatePanelHeightQsExpanded(), mView.getWidth(),
- calculatePanelHeightQsExpanded(), p);
- p.setColor(Color.YELLOW);
- canvas.drawLine(0, calculatePanelHeightShade(), mView.getWidth(),
- calculatePanelHeightShade(), p);
- p.setColor(Color.MAGENTA);
- canvas.drawLine(
- 0, calculateNotificationsTopPadding(), mView.getWidth(),
- calculateNotificationsTopPadding(), p);
- p.setColor(Color.CYAN);
+ public void draw(@NonNull Canvas canvas) {
+ mDebugTextUsedYPositions.clear();
+
+ mDebugPaint.setColor(Color.RED);
+ mDebugPaint.setStrokeWidth(2);
+ mDebugPaint.setStyle(Paint.Style.STROKE);
+ mDebugPaint.setTextSize(24);
+ if (mHeaderDebugInfo != null) canvas.drawText(mHeaderDebugInfo, 50, 100, mDebugPaint);
+
+ drawDebugInfo(canvas, getMaxPanelHeight(), Color.RED, "getMaxPanelHeight()");
+ drawDebugInfo(canvas, (int) getExpandedHeight(), Color.BLUE, "getExpandedHeight()");
+ drawDebugInfo(canvas, calculatePanelHeightQsExpanded(), Color.GREEN,
+ "calculatePanelHeightQsExpanded()");
+ drawDebugInfo(canvas, calculatePanelHeightShade(), Color.YELLOW,
+ "calculatePanelHeightShade()");
+ drawDebugInfo(canvas, (int) calculateNotificationsTopPadding(), Color.MAGENTA,
+ "calculateNotificationsTopPadding()");
+ drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY,
+ "mClockPositionResult.clockY");
+
+ mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
- mNotificationStackScrollLayoutController.getTopPadding(), p);
- p.setColor(Color.GRAY);
- canvas.drawLine(0, mClockPositionResult.clockY, mView.getWidth(),
- mClockPositionResult.clockY, p);
+ mNotificationStackScrollLayoutController.getTopPadding(), mDebugPaint);
+ }
+
+ private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
+ mDebugPaint.setColor(color);
+ canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ mView.getWidth(),
+ /* stopY= */ y, mDebugPaint);
+ canvas.drawText(label, /* x= */ 0, /* y= */ computeDebugYTextPosition(y), mDebugPaint);
+ }
+
+ private int computeDebugYTextPosition(int lineY) {
+ if (lineY - mDebugPaint.getTextSize() < 0) {
+ // Avoiding drawing out of bounds
+ lineY += mDebugPaint.getTextSize();
+ }
+ int textY = lineY;
+ while (mDebugTextUsedYPositions.contains(textY)) {
+ textY = (int) (textY + mDebugPaint.getTextSize());
+ }
+ mDebugTextUsedYPositions.add(textY);
+ return textY;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 1030bfd..33f2140 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -127,10 +127,12 @@
int rotationLockSetting =
mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state);
if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+ // This should not happen. Device states that have an ignored setting, should also
+ // specify a fallback device state which is not ignored.
// We won't handle this device state. The same rotation lock setting as before should
// apply and any changes to the rotation lock setting will be written for the previous
// valid device state.
- Log.v(TAG, "Ignoring new device state: " + state);
+ Log.w(TAG, "Missing fallback. Ignoring new device state: " + state);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingsManager.java
index a418c74..bec5fc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingsManager.java
@@ -52,12 +52,14 @@
private final Handler mMainHandler = Handler.getMain();
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
private SparseIntArray mDeviceStateRotationLockSettings;
+ private SparseIntArray mDeviceStateRotationLockFallbackSettings;
private DeviceStateRotationLockSettingsManager(Context context) {
mContentResolver = context.getContentResolver();
mDeviceStateRotationLockDefaults =
context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
+ loadDefaults();
initializeInMemoryMap();
listenForSettingsChange(context);
}
@@ -114,6 +116,11 @@
/** Updates the rotation lock setting for a specified device state. */
public void updateSetting(int deviceState, boolean rotationLocked) {
+ if (mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState) >= 0) {
+ // The setting for this device state is IGNORED, and has a fallback device state.
+ // The setting for that fallback device state should be the changed in this case.
+ deviceState = mDeviceStateRotationLockFallbackSettings.get(deviceState);
+ }
mDeviceStateRotationLockSettings.put(
deviceState,
rotationLocked
@@ -123,16 +130,37 @@
}
/**
- * Returns the {@link DeviceStateRotationLockSetting} for the given device state. If no setting
- * is specified for this device state, it will return {@link
+ * Returns the {@link Settings.Secure.DeviceStateRotationLockSetting} for the given device
+ * state.
+ *
+ * <p>If the setting for this device state is {@link DEVICE_STATE_ROTATION_LOCK_IGNORED}, it
+ * will return the setting for the fallback device state.
+ *
+ * <p>If no fallback is specified for this device state, it will return {@link
* DEVICE_STATE_ROTATION_LOCK_IGNORED}.
*/
@Settings.Secure.DeviceStateRotationLockSetting
public int getRotationLockSetting(int deviceState) {
- return mDeviceStateRotationLockSettings.get(
- deviceState, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ int rotationLockSetting = mDeviceStateRotationLockSettings.get(
+ deviceState, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+ rotationLockSetting = getFallbackRotationLockSetting(deviceState);
+ }
+ return rotationLockSetting;
}
+ private int getFallbackRotationLockSetting(int deviceState) {
+ int indexOfFallbackState = mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState);
+ if (indexOfFallbackState < 0) {
+ Log.w(TAG, "Setting is ignored, but no fallback was specified.");
+ return DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ }
+ int fallbackState = mDeviceStateRotationLockFallbackSettings.valueAt(indexOfFallbackState);
+ return mDeviceStateRotationLockSettings.get(fallbackState,
+ /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ }
+
+
/** Returns true if the rotation is locked for the current device state */
public boolean isRotationLocked(int deviceState) {
return getRotationLockSetting(deviceState) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
@@ -223,21 +251,30 @@
}
private void loadDefaults() {
- if (mDeviceStateRotationLockDefaults.length == 0) {
- Log.w(TAG, "Empty default settings");
- mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */ 0);
- return;
- }
- mDeviceStateRotationLockSettings =
- new SparseIntArray(mDeviceStateRotationLockDefaults.length);
- for (String serializedDefault : mDeviceStateRotationLockDefaults) {
- String[] entry = serializedDefault.split(SEPARATOR_REGEX);
+ mDeviceStateRotationLockSettings = new SparseIntArray(
+ mDeviceStateRotationLockDefaults.length);
+ mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
+ for (String entry : mDeviceStateRotationLockDefaults) {
+ String[] values = entry.split(SEPARATOR_REGEX);
try {
- int key = Integer.parseInt(entry[0]);
- int value = Integer.parseInt(entry[1]);
- mDeviceStateRotationLockSettings.put(key, value);
+ int deviceState = Integer.parseInt(values[0]);
+ int rotationLockSetting = Integer.parseInt(values[1]);
+ if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+ if (values.length == 3) {
+ int fallbackDeviceState = Integer.parseInt(values[2]);
+ mDeviceStateRotationLockFallbackSettings.put(deviceState,
+ fallbackDeviceState);
+ } else {
+ Log.w(TAG,
+ "Rotation lock setting is IGNORED, but values have unexpected "
+ + "size of "
+ + values.length);
+ }
+ }
+ mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
} catch (NumberFormatException e) {
- Log.wtf(TAG, "Error deserializing default settings", e);
+ Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
+ return;
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 3e8e874..73d2b0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
import org.junit.After;
@@ -92,7 +93,8 @@
mock(DumpManager.class),
mock(AutoHideController.class),
mock(LightBarController.class),
- Optional.of(mock(Pip.class))));
+ Optional.of(mock(Pip.class)),
+ Optional.of(mock(BackAnimation.class))));
initializeNavigationBars();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 5003013..9ca898b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -95,6 +95,7 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
@@ -105,7 +106,6 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
import java.util.Optional;
@@ -383,7 +383,8 @@
mAutoHideController,
mAutoHideControllerFactory,
Optional.of(mTelecomManager),
- mInputMethodManager);
+ mInputMethodManager,
+ Optional.of(mock(BackAnimation.class)));
return spy(factory.create(context));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index b832577..25dd23a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -1968,7 +1968,7 @@
}
@Override
- public int compare(ListEntry o1, ListEntry o2) {
+ public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) {
boolean contains1 = mPreferredPackages.contains(
o1.getRepresentativeEntry().getSbn().getPackageName());
boolean contains2 = mPreferredPackages.contains(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index a46b440..8deac94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -24,18 +24,24 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@@ -47,12 +53,15 @@
// captured listeners and pluggables:
private lateinit var promoter: NotifPromoter
private lateinit var peopleSectioner: NotifSectioner
+ private lateinit var peopleComparator: NotifComparator
@Mock private lateinit var pipeline: NotifPipeline
@Mock private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
@Mock private lateinit var channel: NotificationChannel
@Mock private lateinit var headerController: NodeController
private lateinit var entry: NotificationEntry
+ private lateinit var entryA: NotificationEntry
+ private lateinit var entryB: NotificationEntry
private lateinit var coordinator: ConversationCoordinator
@@ -70,8 +79,15 @@
}
peopleSectioner = coordinator.sectioner
+ peopleComparator = coordinator.comparator
entry = NotificationEntryBuilder().setChannel(channel).build()
+
+ val section = NotifSection(peopleSectioner, 0)
+ entryA = NotificationEntryBuilder().setChannel(channel)
+ .setSection(section).setTag("A").build()
+ entryB = NotificationEntryBuilder().setChannel(channel)
+ .setSection(section).setTag("B").build()
}
@Test
@@ -90,4 +106,36 @@
assertTrue(peopleSectioner.isInSection(entry))
assertFalse(peopleSectioner.isInSection(NotificationEntryBuilder().build()))
}
+
+ @Test
+ fun testComparatorIgnoresFromOtherSection() {
+ val e1 = NotificationEntryBuilder().setId(1).setChannel(channel).build()
+ val e2 = NotificationEntryBuilder().setId(2).setChannel(channel).build()
+
+ // wrong section -- never classify
+ assertThat(peopleComparator.compare(e1, e2)).isEqualTo(0)
+ verify(peopleNotificationIdentifier, never()).getPeopleNotificationType(any())
+ }
+
+ @Test
+ fun testComparatorPutsImportantPeopleFirst() {
+ whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
+ .thenReturn(TYPE_IMPORTANT_PERSON)
+ whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
+ .thenReturn(TYPE_PERSON)
+
+ // only put people notifications in this section
+ assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(-1)
+ }
+
+ @Test
+ fun testComparatorEquatesPeopleWithSameType() {
+ whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
+ .thenReturn(TYPE_PERSON)
+ whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
+ .thenReturn(TYPE_PERSON)
+
+ // only put people notifications in this section
+ assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(0)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 917c049..d094749 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -41,6 +41,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -70,6 +71,7 @@
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private HighPriorityProvider mHighPriorityProvider;
+ @Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
@Mock private NotifPipeline mNotifPipeline;
private NotificationEntry mEntry;
@@ -81,7 +83,7 @@
KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
- mKeyguardUpdateMonitor, mHighPriorityProvider);
+ mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider);
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
index f773810..4e309d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -19,6 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -43,6 +44,7 @@
private val mediaContainerController: MediaContainerController = mock()
private val sectionsFeatureManager: NotificationSectionsFeatureManager = mock()
+ private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock()
private val viewBarn: NotifViewBarn = mock()
private var rootController: NodeController = buildFakeController("rootController")
@@ -72,11 +74,13 @@
fakeViewBarn.getViewByEntry(it.getArgument(0))
}
- specBuilder = NodeSpecBuilder(mediaContainerController, sectionsFeatureManager, viewBarn)
+ specBuilder = NodeSpecBuilder(mediaContainerController, sectionsFeatureManager,
+ sectionHeaderVisibilityProvider, viewBarn)
}
@Test
fun testMultipleSectionsWithSameController() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
listOf(
notif(0, section0),
@@ -95,6 +99,7 @@
@Test(expected = RuntimeException::class)
fun testMultipleSectionsWithSameControllerNonConsecutive() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
listOf(
notif(0, section0),
@@ -108,6 +113,7 @@
@Test
fun testSimpleMapping() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
// GIVEN a simple flat list of notifications all in the same headerless section
listOf(
@@ -129,6 +135,7 @@
@Test
fun testSimpleMappingWithMedia() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
// WHEN media controls are enabled
whenever(sectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true)
@@ -154,6 +161,8 @@
@Test
fun testHeaderInjection() {
+ // WHEN section headers are supposed to be visible
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
// GIVEN a flat list of notifications, spread across three sections
listOf(
@@ -177,7 +186,31 @@
}
@Test
+ fun testHeaderSuppression() {
+ // WHEN section headers are supposed to be hidden
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(false)
+ checkOutput(
+ // GIVEN a flat list of notifications, spread across three sections
+ listOf(
+ notif(0, section0),
+ notif(1, section0),
+ notif(2, section1),
+ notif(3, section2)
+ ),
+
+ // THEN each section has its header injected
+ tree(
+ notifNode(0),
+ notifNode(1),
+ notifNode(2),
+ notifNode(3)
+ )
+ )
+ }
+
+ @Test
fun testGroups() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
// GIVEN a mixed list of top-level notifications and groups
listOf(
@@ -218,6 +251,7 @@
@Test
fun testSecondSectionWithNoHeader() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
// GIVEN a middle section with no associated header view
listOf(
@@ -247,6 +281,7 @@
@Test(expected = RuntimeException::class)
fun testRepeatedSectionsThrow() {
+ whenever(sectionHeaderVisibilityProvider.sectionHeadersVisible).thenReturn(true)
checkOutput(
// GIVEN a malformed list where sections are not contiguous
listOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index a8522c7..6364d2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -52,13 +52,14 @@
@SmallTest
public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
- private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"};
+ private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"};
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
- @Mock DeviceStateManager mDeviceStateManager;
- RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
- DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ @Mock
+ private DeviceStateManager mDeviceStateManager;
+ private final RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
+ private DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
private DeviceStateRotationLockSettingsManager mSettingsManager;
private TestableContentResolver mContentResolver;
@@ -93,7 +94,7 @@
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
- .isEqualTo("0:0:1:2");
+ .isEqualTo("0:1:1:2:2:0");
}
@Test
@@ -125,6 +126,31 @@
}
@Test
+ public void whenDeviceStateSwitched_settingIsIgnored_loadsDefaultFallbackSetting() {
+ initializeSettingsWith();
+ mFakeRotationPolicy.setRotationLock(true);
+
+ // State 2 -> Ignored -> Fall back to state 1 which is unlocked
+ mDeviceStateCallback.onStateChanged(2);
+
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+ }
+
+ @Test
+ public void whenDeviceStateSwitched_ignoredSetting_fallbackValueChanges_usesFallbackValue() {
+ initializeSettingsWith(
+ 0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+ 1, DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ 2, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ mFakeRotationPolicy.setRotationLock(false);
+
+ // State 2 -> Ignored -> Fall back to state 1 which is locked
+ mDeviceStateCallback.onStateChanged(2);
+
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+ }
+
+ @Test
public void whenUserChangesSetting_saveSettingForCurrentState() {
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
@@ -159,15 +185,15 @@
}
@Test
- public void whenDeviceStateSwitchedToIgnoredState_newSettingsSaveForPreviousState() {
+ public void whenDeviceStateSwitchedToIgnoredState_noFallback_newSettingsSaveForPreviousState() {
initializeSettingsWith(
- 0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ 8, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateCallback.onStateChanged(1);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onStateChanged(8);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
@@ -178,7 +204,7 @@
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
- .isEqualTo("0:0:1:1");
+ .isEqualTo("1:1:8:0");
}
@Test
@@ -198,12 +224,78 @@
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
}
+ @Test
+ public void onRotationLockStateChanged_newSettingIsPersisted() {
+ initializeSettingsWith(
+ 0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ mDeviceStateCallback.onStateChanged(0);
+
+ mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
+ /* rotationLocked= */ false,
+ /* affordanceVisible= */ true
+ );
+
+ assertThat(
+ Settings.Secure.getStringForUser(
+ mContentResolver,
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:2:1:2");
+ }
+
+ @Test
+ public void onRotationLockStateChanged_deviceStateIsIgnored_newSettingIsPersistedToFallback() {
+ initializeSettingsWith(
+ 0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+ 2, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ mDeviceStateCallback.onStateChanged(2);
+
+ mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
+ /* rotationLocked= */ true,
+ /* affordanceVisible= */ true
+ );
+
+ assertThat(
+ Settings.Secure.getStringForUser(
+ mContentResolver,
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:1:1:1:2:0");
+ }
+
+ @Test
+ public void onRotationLockStateChange_stateIgnored_noFallback_settingIsPersistedToPrevious() {
+ initializeSettingsWith(
+ 0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+ 8, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ mDeviceStateCallback.onStateChanged(1);
+ mDeviceStateCallback.onStateChanged(8);
+
+ mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
+ /* rotationLocked= */ true,
+ /* affordanceVisible= */ true
+ );
+
+ assertThat(
+ Settings.Secure.getStringForUser(
+ mContentResolver,
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:1:1:1:8:0");
+ }
+
private void initializeSettingsWith(int... values) {
if (values.length % 2 != 0) {
throw new IllegalArgumentException("Expecting key-value pairs");
}
StringBuilder sb = new StringBuilder();
- for (int i = 0; i < values.length; sb.append(":")) {
+ for (int i = 0; i < values.length; ) {
+ if (i > 0) {
+ sb.append(":");
+ }
sb.append(values[i++]).append(":").append(values[i++]);
}
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 93fc0e72..2b7b977 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -254,9 +254,14 @@
private AssociationInfo createAssociationAndNotifyApplication(
@NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId,
@Nullable MacAddress macAddress, @NonNull IAssociationRequestCallback callback) {
- final AssociationInfo association = mService.createAssociation(userId, packageName,
- macAddress, request.getDisplayName(), request.getDeviceProfile(),
- request.isSelfManaged());
+ final AssociationInfo association;
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ association = mService.createAssociation(userId, packageName, macAddress,
+ request.getDisplayName(), request.getDeviceProfile(), request.isSelfManaged());
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
try {
callback.onAssociationCreated(association);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index b2b5576..cfd3798 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -787,6 +787,12 @@
Slog.i(LOG_TAG, "New CDM association created=" + association);
mAssociationStore.addAssociation(association);
+ // If the "Device Profile" is specified, make the companion application a holder of the
+ // corresponding role.
+ if (deviceProfile != null) {
+ addRoleHolderForAssociation(getContext(), association);
+ }
+
updateSpecialAccessPermissionForAssociatedPackage(association);
return association;
@@ -930,14 +936,8 @@
exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);
- if (!association.isSelfManaged()) {
- if (mCurrentlyConnectedDevices.contains(association.getDeviceMacAddressAsString())) {
- addRoleHolderForAssociation(getContext(), association);
- }
-
- if (association.isNotifyOnDeviceNearby()) {
- restartBleScan();
- }
+ if (association.isNotifyOnDeviceNearby()) {
+ restartBleScan();
}
}
@@ -983,19 +983,7 @@
void onDeviceConnected(String address) {
Slog.d(LOG_TAG, "onDeviceConnected(address = " + address + ")");
-
mCurrentlyConnectedDevices.add(address);
-
- for (AssociationInfo association : mAssociationStore.getAssociationsByAddress(address)) {
- if (association.getDeviceProfile() != null) {
- Slog.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
- + " to " + association.getPackageName()
- + " due to device connected: " + association.getDeviceMacAddress());
-
- addRoleHolderForAssociation(getContext(), association);
- }
- }
-
onDeviceNearby(address);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 9b2bd82..f2e66077 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -73,20 +73,12 @@
}
break;
- case "simulate_connect": {
- mService.onDeviceConnected(getNextArgRequired());
- }
- break;
-
- case "simulate_disconnect": {
- mService.onDeviceDisconnected(getNextArgRequired());
- }
- break;
case "clear-association-memory-cache": {
mService.persistState();
mService.loadAssociationsFromDisk();
}
break;
+
default:
return handleDefaultCommands(cmd);
}
diff --git a/services/companion/java/com/android/server/companion/DataStoreUtils.java b/services/companion/java/com/android/server/companion/DataStoreUtils.java
new file mode 100644
index 0000000..6055a81
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/DataStoreUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.companion;
+
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+
+import com.android.internal.util.FunctionalUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+final class DataStoreUtils {
+
+ private static final String LOG_TAG = DataStoreUtils.class.getSimpleName();
+
+ static boolean isStartOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
+ throws XmlPullParserException {
+ return parser.getEventType() == START_TAG && tag.equals(parser.getName());
+ }
+
+ static boolean isEndOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
+ throws XmlPullParserException {
+ return parser.getEventType() == END_TAG && tag.equals(parser.getName());
+ }
+
+ /**
+ * Creates {@link AtomicFile} object that represents the back-up for the given user.
+ *
+ * IMPORTANT: the method will ALWAYS return the same {@link AtomicFile} object, which makes it
+ * possible to synchronize reads and writes to the file using the returned object.
+ *
+ * @param userId the userId to retrieve the storage file
+ * @param fileName the storage file name
+ * @return an AtomicFile for the user
+ */
+ @NonNull
+ static AtomicFile createStorageFileForUser(@UserIdInt int userId, String fileName) {
+ return new AtomicFile(getBaseStorageFileForUser(userId, fileName));
+ }
+
+ @NonNull
+ private static File getBaseStorageFileForUser(@UserIdInt int userId, String fileName) {
+ return new File(Environment.getDataSystemDeDirectory(userId), fileName);
+ }
+
+ /**
+ * Writing to file could fail, for example, if the user has been recently removed and so was
+ * their DE (/data/system_de/<user-id>/) directory.
+ */
+ static void writeToFileSafely(@NonNull AtomicFile file,
+ @NonNull FunctionalUtils.ThrowingConsumer<FileOutputStream> consumer) {
+ try {
+ file.write(consumer);
+ } catch (Exception e) {
+ Slog.e(LOG_TAG, "Error while writing to file " + file, e);
+ }
+ }
+
+ private DataStoreUtils() {
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 3c8c3cb..da33b44 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -25,9 +25,10 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
-import static org.xmlpull.v1.XmlPullParser.END_TAG;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
+import static com.android.server.companion.DataStoreUtils.isEndOfTag;
+import static com.android.server.companion.DataStoreUtils.isStartOfTag;
+import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -44,7 +45,6 @@
import android.util.TypedXmlSerializer;
import android.util.Xml;
-import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -53,7 +53,6 @@
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
@@ -210,6 +209,7 @@
@NonNull Collection<AssociationInfo> associationsOut,
@NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackageOut) {
Slog.i(LOG_TAG, "Reading associations for user " + userId + " from disk");
+
final AtomicFile file = getStorageFileForUser(userId);
if (DEBUG) Slog.d(LOG_TAG, " > File=" + file.getBaseFile().getPath());
@@ -349,11 +349,7 @@
*/
private @NonNull AtomicFile getStorageFileForUser(@UserIdInt int userId) {
return mUserIdToStorageFile.computeIfAbsent(userId,
- u -> new AtomicFile(getBaseStorageFileForUser(userId)));
- }
-
- private static @NonNull File getBaseStorageFileForUser(@UserIdInt int userId) {
- return new File(Environment.getDataSystemDeDirectory(userId), FILE_NAME);
+ u -> createStorageFileForUser(userId, FILE_NAME));
}
private static @NonNull File getBaseLegacyStorageFileForUser(@UserIdInt int userId) {
@@ -512,16 +508,6 @@
serializer.endTag(null, XML_TAG_PACKAGE);
}
- private static boolean isStartOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
- throws XmlPullParserException {
- return parser.getEventType() == START_TAG && tag.equals(parser.getName());
- }
-
- private static boolean isEndOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
- throws XmlPullParserException {
- return parser.getEventType() == END_TAG && tag.equals(parser.getName());
- }
-
private static void requireStartOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
throws XmlPullParserException {
if (isStartOfTag(parser, tag)) return;
@@ -546,13 +532,4 @@
}
return associationInfo;
}
-
- private static void writeToFileSafely(@NonNull AtomicFile file,
- @NonNull ThrowingConsumer<FileOutputStream> consumer) {
- try {
- file.write(consumer);
- } catch (Exception e) {
- Slog.e(LOG_TAG, "Error while writing to file " + file, e);
- }
- }
}
diff --git a/services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java b/services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java
new file mode 100644
index 0000000..38e5d16
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2022 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.companion;
+
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readThisListXml;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeListXml;
+import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
+import static com.android.server.companion.DataStoreUtils.isEndOfTag;
+import static com.android.server.companion.DataStoreUtils.isStartOfTag;
+import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.companion.SystemDataTransferRequest;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * The class is responsible for reading/writing SystemDataTransferRequest records from/to the disk.
+ *
+ * The following snippet is a sample XML file stored in the disk.
+ * <pre>{@code
+ * <requests>
+ * <request
+ * association_id="1"
+ * is_permission_sync_all_packages="false">
+ * <list name="permission_sync_packages">
+ * <string>com.sample.app1</string>
+ * <string>com.sample.app2</string>
+ * </list>
+ * </request>
+ * </requests>
+ * }</pre>
+ */
+public class SystemDataTransferRequestDataStore {
+
+ private static final String LOG_TAG = SystemDataTransferRequestDataStore.class.getSimpleName();
+
+ private static final String FILE_NAME = "companion_device_system_data_transfer_requests.xml";
+
+ private static final String XML_TAG_REQUESTS = "requests";
+ private static final String XML_TAG_REQUEST = "request";
+ private static final String XML_TAG_LIST = "list";
+
+ private static final String XML_ATTR_ASSOCIATION_ID = "association_id";
+ private static final String XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES =
+ "is_permission_sync_all_packages";
+ private static final String XML_ATTR_PERMISSION_SYNC_PACKAGES = "permission_sync_packages";
+
+ private final ConcurrentMap<Integer, AtomicFile> mUserIdToStorageFile =
+ new ConcurrentHashMap<>();
+
+ /**
+ * Reads previously persisted data for the given user
+ *
+ * @param userId Android UserID
+ * @return a list of SystemDataTransferRequest
+ */
+ @NonNull
+ List<SystemDataTransferRequest> readRequestsForUser(@UserIdInt int userId) {
+ final AtomicFile file = getStorageFileForUser(userId);
+ Slog.i(LOG_TAG, "Reading SystemDataTransferRequests for user " + userId + " from "
+ + "file=" + file.getBaseFile().getPath());
+
+ // getStorageFileForUser() ALWAYS returns the SAME OBJECT, which allows us to synchronize
+ // accesses to the file on the file system using this AtomicFile object.
+ synchronized (file) {
+ if (!file.getBaseFile().exists()) {
+ Slog.d(LOG_TAG, "File does not exist -> Abort");
+ return Collections.emptyList();
+ }
+ try (FileInputStream in = file.openRead()) {
+ final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ XmlUtils.beginDocument(parser, XML_TAG_REQUESTS);
+
+ return readRequests(parser);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(LOG_TAG, "Error while reading requests file", e);
+ return Collections.emptyList();
+ }
+ }
+ }
+
+ @NonNull
+ private List<SystemDataTransferRequest> readRequests(@NonNull TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (!isStartOfTag(parser, XML_TAG_REQUESTS)) {
+ throw new XmlPullParserException("The XML doesn't have start tag: " + XML_TAG_REQUESTS);
+ }
+
+ List<SystemDataTransferRequest> requests = new ArrayList<>();
+
+ while (true) {
+ parser.nextTag();
+ if (isEndOfTag(parser, XML_TAG_REQUESTS)) break;
+ if (isStartOfTag(parser, XML_TAG_REQUEST)) {
+ requests.add(readRequest(parser));
+ }
+ }
+
+ return requests;
+ }
+
+ private SystemDataTransferRequest readRequest(@NonNull TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (!isStartOfTag(parser, XML_TAG_REQUEST)) {
+ throw new XmlPullParserException("XML doesn't have start tag: " + XML_TAG_REQUEST);
+ }
+
+ final int associationId = readIntAttribute(parser, XML_ATTR_ASSOCIATION_ID);
+ final boolean isPermissionSyncAllPackages = readBooleanAttribute(parser,
+ XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES);
+ parser.nextTag();
+ List<String> permissionSyncPackages = new ArrayList<>();
+ if (isStartOfTag(parser, XML_TAG_LIST)) {
+ parser.nextTag();
+ permissionSyncPackages = readThisListXml(parser, XML_TAG_LIST,
+ new String[1]);
+ }
+
+ return new SystemDataTransferRequest(associationId, isPermissionSyncAllPackages,
+ permissionSyncPackages);
+ }
+
+ /**
+ * Persisted user's SystemDataTransferRequest data to the disk.
+ *
+ * @param userId Android UserID
+ * @param requests a list of user's SystemDataTransferRequest.
+ */
+ void writeRequestsForUser(@UserIdInt int userId,
+ @NonNull List<SystemDataTransferRequest> requests) {
+ final AtomicFile file = getStorageFileForUser(userId);
+ Slog.i(LOG_TAG, "Writing SystemDataTransferRequests for user " + userId + " to file="
+ + file.getBaseFile().getPath());
+
+ // getStorageFileForUser() ALWAYS returns the SAME OBJECT, which allows us to synchronize
+ // accesses to the file on the file system using this AtomicFile object.
+ synchronized (file) {
+ writeToFileSafely(file, out -> {
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+ writeRequests(serializer, requests);
+ serializer.endDocument();
+ });
+ }
+ }
+
+ private void writeRequests(@NonNull TypedXmlSerializer serializer,
+ @Nullable Collection<SystemDataTransferRequest> requests) throws IOException {
+ serializer.startTag(null, XML_TAG_REQUESTS);
+
+ for (SystemDataTransferRequest request : requests) {
+ writeRequest(serializer, request);
+ }
+
+ serializer.endTag(null, XML_TAG_REQUESTS);
+ }
+
+ private void writeRequest(@NonNull TypedXmlSerializer serializer,
+ @NonNull SystemDataTransferRequest request) throws IOException {
+ serializer.startTag(null, XML_TAG_REQUEST);
+
+ writeIntAttribute(serializer, XML_ATTR_ASSOCIATION_ID, request.getAssociationId());
+ writeBooleanAttribute(serializer, XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES,
+ request.isPermissionSyncAllPackages());
+ try {
+ writeListXml(request.getPermissionSyncPackages(), XML_ATTR_PERMISSION_SYNC_PACKAGES,
+ serializer);
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Error writing permission sync packages into XML. "
+ + request.getPermissionSyncPackages().toString());
+ }
+
+ serializer.endTag(null, XML_TAG_REQUEST);
+ }
+
+ /**
+ * Creates and caches {@link AtomicFile} object that represents the back-up file for the given
+ * user.
+ *
+ * IMPORTANT: the method will ALWAYS return the same {@link AtomicFile} object, which makes it
+ * possible to synchronize reads and writes to the file using the returned object.
+ */
+ private @NonNull AtomicFile getStorageFileForUser(@UserIdInt int userId) {
+ return mUserIdToStorageFile.computeIfAbsent(userId,
+ u -> createStorageFileForUser(userId, FILE_NAME));
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
new file mode 100644
index 0000000..0eb6b8d
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2022 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.companion.presence;
+
+import static android.bluetooth.BluetoothAdapter.ACTION_BLE_STATE_CHANGED;
+import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
+import static android.bluetooth.BluetoothAdapter.EXTRA_PREVIOUS_STATE;
+import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
+import static android.bluetooth.BluetoothAdapter.STATE_BLE_ON;
+import static android.bluetooth.BluetoothAdapter.STATE_ON;
+import static android.bluetooth.BluetoothAdapter.nameForState;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_ALREADY_STARTED;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES;
+import static android.bluetooth.le.ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY;
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_FIRST_MATCH;
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_MATCH_LOST;
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
+
+import static com.android.server.companion.presence.Utils.btDeviceToString;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.companion.AssociationInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.companion.AssociationStore;
+import com.android.server.companion.AssociationStore.ChangeType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SuppressLint("LongLogTag")
+class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "CompanionDevice_PresenceMonitor_BLE";
+
+ /**
+ * When using {@link ScanSettings#SCAN_MODE_LOW_POWER}, it usually takes from 20 seconds to
+ * 2 minutes for the BLE scanner to find advertisements sent from the same device.
+ * On the other hand, {@link android.bluetooth.BluetoothAdapter.LeScanCallback} will report
+ * {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST MATCH_LOST} 10 sec after it finds the
+ * advertisement for the first time (add reports
+ * {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH FIRST_MATCH}).
+ * To avoid constantly reporting {@link Callback#onBleCompanionDeviceFound(int) onDeviceFound()}
+ * and {@link Callback#onBleCompanionDeviceLost(int) onDeviceLost()} (while the device is
+ * actually present) to its clients, {@link BleCompanionDeviceScanner}, will add 1-minute delay
+ * after it receives {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST MATCH_LOST}.
+ */
+ private static final int NOTIFY_DEVICE_LOST_DELAY = 2 * 60 * 1000; // 2 Min.
+
+ interface Callback {
+ void onBleCompanionDeviceFound(int associationId);
+
+ void onBleCompanionDeviceLost(int associationId);
+ }
+
+ private final @NonNull AssociationStore mAssociationStore;
+ private final @NonNull Callback mCallback;
+ private final @NonNull MainThreadHandler mMainThreadHandler;
+
+ // Non-null after init().
+ private @Nullable BluetoothAdapter mBtAdapter;
+ // Non-null after init() and when BLE is available. Otherwise - null.
+ private @Nullable BluetoothLeScanner mBleScanner;
+ // Only accessed from the Main thread.
+ private boolean mScanning = false;
+
+ BleCompanionDeviceScanner(
+ @NonNull AssociationStore associationStore, @NonNull Callback callback) {
+ mAssociationStore = associationStore;
+ mCallback = callback;
+ mMainThreadHandler = new MainThreadHandler();
+ }
+
+ @MainThread
+ void init(@NonNull Context context, @NonNull BluetoothAdapter btAdapter) {
+ if (DEBUG) Log.i(TAG, "init()");
+
+ if (mBtAdapter != null) {
+ throw new IllegalStateException(getClass().getSimpleName() + " is already initialized");
+ }
+ mBtAdapter = requireNonNull(btAdapter);
+
+ checkBleState();
+ registerBluetoothStateBroadcastReceiver(context);
+
+ mAssociationStore.registerListener(this);
+ }
+
+ @MainThread
+ final void restartScan() {
+ enforceInitialized();
+
+ if (DEBUG) Log.i(TAG , "restartScan()");
+ if (mBleScanner == null) {
+ if (DEBUG) Log.d(TAG, " > BLE is not available");
+ return;
+ }
+
+ stopScanIfNeeded();
+ startScan();
+ }
+
+ @Override
+ public void onAssociationChanged(@ChangeType int changeType, AssociationInfo association) {
+ // Simply restart scanning.
+ if (Looper.getMainLooper().isCurrentThread()) {
+ restartScan();
+ } else {
+ mMainThreadHandler.post(this::restartScan);
+ }
+ }
+
+ @MainThread
+ private void checkBleState() {
+ enforceInitialized();
+
+ final boolean bleAvailable = isBleAvailable();
+ if (DEBUG) {
+ Log.i(TAG, "checkBleState() bleAvailable=" + bleAvailable);
+ }
+ if ((bleAvailable && mBleScanner != null) || (!bleAvailable && mBleScanner == null)) {
+ // Nothing changed.
+ if (DEBUG) Log.i(TAG, " > BLE status did not change");
+ return;
+ }
+
+ if (bleAvailable) {
+ mBleScanner = mBtAdapter.getBluetoothLeScanner();
+ if (mBleScanner == null) {
+ // Oops, that's a race condition. Can return.
+ return;
+ }
+ if (DEBUG) Log.i(TAG, " > BLE is now available");
+
+ startScan();
+ } else {
+ if (DEBUG) Log.i(TAG, " > BLE is now unavailable");
+
+ stopScanIfNeeded();
+ mBleScanner = null;
+ }
+ }
+
+ /**
+ * A duplicate of {@code BluetoothAdapter.getLeAccess()} method which has the package-private
+ * access level, so it's not accessible from here.
+ */
+ private boolean isBleAvailable() {
+ final int state = mBtAdapter.getLeState();
+ if (DEBUG) Log.d(TAG, "getLeAccess() state=" + nameForBtState(state));
+ return state == STATE_ON || state == STATE_BLE_ON;
+ }
+
+ @MainThread
+ private void startScan() {
+ enforceInitialized();
+ // This method should not be called if scan is already in progress.
+ if (mScanning) throw new IllegalStateException("Scan is already in progress.");
+ // Neither should this method be called if the adapter is not available.
+ if (mBleScanner == null) throw new IllegalStateException("BLE is not available.");
+
+ if (DEBUG) Log.i(TAG, "startScan()");
+
+ // Collect MAC addresses from all associations.
+ final Set<String> macAddresses = new HashSet<>();
+ for (AssociationInfo association : mAssociationStore.getAssociations()) {
+ // Beware that BT stack does not consider low-case MAC addresses valid, while
+ // MacAddress.toString() return a low-case String.
+ final String macAddress = association.getDeviceMacAddressAsString();
+ if (macAddress != null) {
+ macAddresses.add(macAddress);
+ }
+ }
+ if (macAddresses.isEmpty()) {
+ if (DEBUG) Log.i(TAG, " > there are no (associated) devices to Scan for.");
+ return;
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, " > addresses=(n=" + macAddresses.size() + ")"
+ + "[" + String.join(", ", macAddresses) + "]");
+ }
+ }
+
+ final List<ScanFilter> filters = new ArrayList<>(macAddresses.size());
+ for (String macAddress : macAddresses) {
+ final ScanFilter filter = new ScanFilter.Builder()
+ .setDeviceAddress(macAddress)
+ .build();
+ filters.add(filter);
+ }
+
+ mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback);
+ mScanning = true;
+ }
+
+ private void stopScanIfNeeded() {
+ enforceInitialized();
+
+ if (DEBUG) Log.i(TAG, "stopScan()");
+ if (!mScanning) {
+ Log.d(TAG, " > not scanning.");
+ return;
+ }
+
+ mBleScanner.stopScan(mScanCallback);
+ mScanning = false;
+ }
+
+ @MainThread
+ private void notifyDeviceFound(@NonNull BluetoothDevice device) {
+ if (DEBUG) Log.i(TAG, "notifyDevice_Found()" + btDeviceToString(device));
+
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(device.getAddress());
+ if (DEBUG) Log.d(TAG, " > associations=" + Arrays.toString(associations.toArray()));
+
+ for (AssociationInfo association : associations) {
+ mCallback.onBleCompanionDeviceFound(association.getId());
+ }
+ }
+
+ @MainThread
+ private void notifyDeviceLost(@NonNull BluetoothDevice device) {
+ if (DEBUG) Log.i(TAG, "notifyDevice_Lost()" + btDeviceToString(device));
+
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(device.getAddress());
+ if (DEBUG) Log.d(TAG, " > associations=" + Arrays.toString(associations.toArray()));
+
+ for (AssociationInfo association : associations) {
+ mCallback.onBleCompanionDeviceLost(association.getId());
+ }
+ }
+
+ private void registerBluetoothStateBroadcastReceiver(Context context) {
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_STATE, -1);
+ final int state = intent.getIntExtra(EXTRA_STATE, -1);
+
+ if (DEBUG) {
+ // The action is either STATE_CHANGED or BLE_STATE_CHANGED.
+ final String action =
+ intent.getAction().replace("android.bluetooth.adapter.", "bt.");
+ Log.d(TAG, "on(Broadcast)Receive() " + action + ": "
+ + nameForBtState(prevState) + "->" + nameForBtState(state));
+ }
+
+ checkBleState();
+ }
+ };
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_STATE_CHANGED);
+ filter.addAction(ACTION_BLE_STATE_CHANGED);
+
+ context.registerReceiver(receiver, filter);
+ }
+
+ private void enforceInitialized() {
+ if (mBtAdapter != null) return;
+ throw new IllegalStateException(getClass().getSimpleName() + " is not initialized");
+ }
+
+ private final ScanCallback mScanCallback = new ScanCallback() {
+ @MainThread
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ final BluetoothDevice device = result.getDevice();
+
+ if (DEBUG) {
+ Log.d(TAG, "onScanResult() " + nameForBleScanCallbackType(callbackType)
+ + " device=" + btDeviceToString(device));
+ Log.v(TAG, " > scanResult=" + result);
+
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(device.getAddress());
+ Log.v(TAG, " > associations=" + Arrays.toString(associations.toArray()));
+ }
+
+ switch (callbackType) {
+ case CALLBACK_TYPE_FIRST_MATCH:
+ if (mMainThreadHandler.hasNotifyDeviceLostMessages(device)) {
+ mMainThreadHandler.removeNotifyDeviceLostMessages(device);
+ return;
+ }
+
+ notifyDeviceFound(device);
+ break;
+
+ case CALLBACK_TYPE_MATCH_LOST:
+ mMainThreadHandler.sendNotifyDeviceLostDelayedMessage(device);
+ break;
+
+ default:
+ Slog.wtf(TAG, "Unexpected callback "
+ + nameForBleScanCallbackType(callbackType));
+ break;
+ }
+ }
+
+ @MainThread
+ @Override
+ public void onScanFailed(int errorCode) {
+ if (DEBUG) Log.w(TAG, "onScanFailed() " + nameForBleScanErrorCode(errorCode));
+ mScanning = false;
+ }
+ };
+
+ @SuppressLint("HandlerLeak")
+ private class MainThreadHandler extends Handler {
+ private static final int NOTIFY_DEVICE_LOST = 1;
+
+ MainThreadHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message message) {
+ if (message.what != NOTIFY_DEVICE_LOST) return;
+
+ final BluetoothDevice device = (BluetoothDevice) message.obj;
+ notifyDeviceLost(device);
+ }
+
+ void sendNotifyDeviceLostDelayedMessage(BluetoothDevice device) {
+ final Message message = obtainMessage(NOTIFY_DEVICE_LOST, device);
+ sendMessageDelayed(message, NOTIFY_DEVICE_LOST_DELAY);
+ }
+
+ boolean hasNotifyDeviceLostMessages(BluetoothDevice device) {
+ return hasEqualMessages(NOTIFY_DEVICE_LOST, device);
+ }
+
+ void removeNotifyDeviceLostMessages(BluetoothDevice device) {
+ removeEqualMessages(NOTIFY_DEVICE_LOST, device);
+ }
+ }
+
+ private static String nameForBtState(int state) {
+ return nameForState(state) + "(" + state + ")";
+ }
+
+ private static String nameForBleScanCallbackType(int callbackType) {
+ final String name;
+ switch (callbackType) {
+ case CALLBACK_TYPE_ALL_MATCHES:
+ name = "ALL_MATCHES";
+ break;
+ case CALLBACK_TYPE_FIRST_MATCH:
+ name = "FIRST_MATCH";
+ break;
+ case CALLBACK_TYPE_MATCH_LOST:
+ name = "MATCH_LOST";
+ break;
+ default:
+ name = "Unknown";
+ }
+ return name + "(" + callbackType + ")";
+ }
+
+ private static String nameForBleScanErrorCode(int errorCode) {
+ final String name;
+ switch (errorCode) {
+ case SCAN_FAILED_ALREADY_STARTED:
+ name = "ALREADY_STARTED";
+ break;
+ case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
+ name = "APPLICATION_REGISTRATION_FAILED";
+ break;
+ case SCAN_FAILED_INTERNAL_ERROR:
+ name = "INTERNAL_ERROR";
+ break;
+ case SCAN_FAILED_FEATURE_UNSUPPORTED:
+ name = "FEATURE_UNSUPPORTED";
+ break;
+ case SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES:
+ name = "OUT_OF_HARDWARE_RESOURCES";
+ break;
+ case SCAN_FAILED_SCANNING_TOO_FREQUENTLY:
+ name = "SCANNING_TOO_FREQUENTLY";
+ break;
+ default:
+ name = "Unknown";
+ }
+ return name + "(" + errorCode + ")";
+ }
+
+ private static final ScanSettings SCAN_SETTINGS = new ScanSettings.Builder()
+ .setCallbackType(CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST)
+ .setScanMode(SCAN_MODE_LOW_POWER)
+ .build();
+}
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index a4fa1c1..dbe866b 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -16,6 +16,8 @@
package com.android.server.companion.presence;
+import static com.android.server.companion.presence.Utils.btDeviceToString;
+
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
@@ -71,11 +73,11 @@
*/
@Override
public void onDeviceConnected(@NonNull BluetoothDevice device) {
- if (DEBUG) Log.i(TAG, "onDevice_Connected() " + toString(device));
+ if (DEBUG) Log.i(TAG, "onDevice_Connected() " + btDeviceToString(device));
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
if (mAllConnectedDevices.put(macAddress, device) != null) {
- if (DEBUG) Log.w(TAG, "Device " + toString(device) + " is already connected.");
+ if (DEBUG) Log.w(TAG, "Device " + btDeviceToString(device) + " is already connected.");
return;
}
@@ -91,13 +93,15 @@
public void onDeviceDisconnected(@NonNull BluetoothDevice device,
@DisconnectReason int reason) {
if (DEBUG) {
- Log.i(TAG, "onDevice_Disconnected() " + toString(device));
+ Log.i(TAG, "onDevice_Disconnected() " + btDeviceToString(device));
Log.d(TAG, " reason=" + disconnectReasonText(reason));
}
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
if (mAllConnectedDevices.remove(macAddress) == null) {
- if (DEBUG) Log.w(TAG, "The device wasn't tracked as connected " + toString(device));
+ if (DEBUG) {
+ Log.w(TAG, "The device wasn't tracked as connected " + btDeviceToString(device));
+ }
return;
}
@@ -109,7 +113,7 @@
mAssociationStore.getAssociationsByAddress(device.getAddress());
if (DEBUG) {
- Log.d(TAG, "onDevice_ConnectivityChanged() " + toString(device)
+ Log.d(TAG, "onDevice_ConnectivityChanged() " + btDeviceToString(device)
+ " connected=" + connected);
if (associations.isEmpty()) {
Log.d(TAG, " > No CDM associations");
@@ -138,6 +142,12 @@
}
@Override
+ public void onAssociationRemoved(AssociationInfo association) {
+ // Intentionally do nothing: CompanionDevicePresenceMonitor will do all the bookkeeping
+ // required.
+ }
+
+ @Override
public void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {
if (DEBUG) {
Log.d(TAG, "onAssociation_Updated() addrChange=" + addressChanged
@@ -153,23 +163,4 @@
// This will be implemented when CDM support updating addresses.
throw new IllegalArgumentException("Address changes are not supported.");
}
-
- private static String toString(@NonNull BluetoothDevice btDevice) {
- final StringBuilder sb = new StringBuilder(btDevice.getAddress());
-
- sb.append(" [name=");
- final String name = btDevice.getName();
- if (name != null) {
- sb.append('\'').append(name).append('\'');
- } else {
- sb.append("null");
- }
-
- final String alias = btDevice.getAlias();
- if (alias != null) {
- sb.append(", alias='").append(alias).append("'");
- }
-
- return sb.append(']').toString();
- }
}
diff --git a/services/companion/java/com/android/server/companion/presence/Utils.java b/services/companion/java/com/android/server/companion/presence/Utils.java
new file mode 100644
index 0000000..583b443
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/presence/Utils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.companion.presence;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothDevice;
+
+/** Utilities for working with Bluetooth and BLE devices. */
+class Utils {
+
+ /**
+ * @return short String representation of {@link BluetoothDevice}.
+ */
+ static String btDeviceToString(@NonNull BluetoothDevice btDevice) {
+ final StringBuilder sb = new StringBuilder(btDevice.getAddress());
+
+ sb.append(" [name=");
+ final String name = btDevice.getName();
+ if (name != null) {
+ sb.append('\'').append(name).append('\'');
+ } else {
+ sb.append("null");
+ }
+
+ final String alias = btDevice.getAlias();
+ if (alias != null) {
+ sb.append(", alias='").append(alias).append("'");
+ }
+
+ return sb.append(']').toString();
+ }
+
+ private Utils() {
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e040319..8887108 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4138,7 +4138,7 @@
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
- app = r.isolatedProc;
+ app = r.isolationHostProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
@@ -4165,7 +4165,7 @@
return msg;
}
if (isolated) {
- r.isolatedProc = app;
+ r.isolationHostProc = app;
}
}
@@ -4976,7 +4976,7 @@
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
- if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
+ if (proc != sr.isolationHostProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
@@ -5016,7 +5016,7 @@
boolean didImmediateRestart = false;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
- if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
+ if (proc != sr.isolationHostProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
@@ -5048,9 +5048,9 @@
ServiceRecord sr = mPendingServices.get(i);
if ((proc.uid == sr.appInfo.uid
&& proc.processName.equals(sr.processName))
- || sr.isolatedProc == proc) {
+ || sr.isolationHostProc == proc) {
Slog.w(TAG, "Forcing bringing down service: " + sr);
- sr.isolatedProc = null;
+ sr.isolationHostProc = null;
mPendingServices.remove(i);
size = mPendingServices.size();
i--;
@@ -5083,7 +5083,7 @@
stopServiceAndUpdateAllowlistManagerLocked(service);
}
service.setProcess(null, null, 0, null);
- service.isolatedProc = null;
+ service.isolationHostProc = null;
if (mTmpCollectionResults == null) {
mTmpCollectionResults = new ArrayList<>();
}
@@ -5321,7 +5321,7 @@
sr.app.mServices.updateBoundClientUids();
}
sr.setProcess(null, null, 0, null);
- sr.isolatedProc = null;
+ sr.isolationHostProc = null;
sr.executeNesting = 0;
synchronized (mAm.mProcessStats.mLock) {
sr.forceClearTracker();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b123496..bdfd02e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -598,7 +598,7 @@
for (int i = psr.numberOfConnections() - 1; i >= 0; i--) {
ConnectionRecord cr = psr.getConnectionAt(i);
ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
- ? cr.binding.service.isolatedProc : cr.binding.service.app;
+ ? cr.binding.service.isolationHostProc : cr.binding.service.app;
if (service == null || service == pr) {
continue;
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c830554..be187e2 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -513,7 +513,7 @@
}
}
processInfo = procInfo;
- isolated = _info.uid != _uid;
+ isolated = Process.isIsolated(_uid);
appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
&& UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
uid = _uid;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 9b32e61..24e7ba4 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -102,7 +102,8 @@
// IBinder -> ConnectionRecord of all bound clients
ProcessRecord app; // where this service is running or null.
- ProcessRecord isolatedProc; // keep track of isolated process, if requested
+ ProcessRecord isolationHostProc; // process which we've started for this service (used for
+ // isolated and supplemental processes)
ServiceState tracker; // tracking service execution, may be null
ServiceState restartTracker; // tracking service restart
boolean allowlistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
@@ -352,8 +353,8 @@
if (app != null) {
app.dumpDebug(proto, ServiceRecordProto.APP);
}
- if (isolatedProc != null) {
- isolatedProc.dumpDebug(proto, ServiceRecordProto.ISOLATED_PROC);
+ if (isolationHostProc != null) {
+ isolationHostProc.dumpDebug(proto, ServiceRecordProto.ISOLATED_PROC);
}
proto.write(ServiceRecordProto.WHITELIST_MANAGER, allowlistManager);
proto.write(ServiceRecordProto.DELAYED, delayed);
@@ -455,8 +456,8 @@
pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
}
pw.print(prefix); pw.print("app="); pw.println(app);
- if (isolatedProc != null) {
- pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
+ if (isolationHostProc != null) {
+ pw.print(prefix); pw.print("isolationHostProc="); pw.println(isolationHostProc);
}
if (allowlistManager) {
pw.print(prefix); pw.print("allowlistManager="); pw.println(allowlistManager);
diff --git a/services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java b/services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java
index c985d5d..f7b73688 100644
--- a/services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java
+++ b/services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
/**
* Client monitor callback that exposes a probe.
@@ -27,7 +28,7 @@
*
* @param <T> probe type
*/
-public class CallbackWithProbe<T extends Probe> implements BaseClientMonitor.Callback {
+public class CallbackWithProbe<T extends Probe> implements ClientMonitorCallback {
private final boolean mStartWithClient;
private final T mProbe;
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index e29caa8..86d72ba 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -138,7 +138,7 @@
}
@Override
- public void cancelWithoutStarting(@NonNull Callback callback) {
+ public void cancelWithoutStarting(@NonNull ClientMonitorCallback callback) {
Slog.d(TAG, "cancelWithoutStarting: " + this);
final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED;
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 0eb5aaf..35a0f57 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -91,7 +91,7 @@
/**
* Handles lifecycle, e.g. {@link BiometricScheduler},
- * {@link com.android.server.biometrics.sensors.BaseClientMonitor.Callback} after authentication
+ * {@link ClientMonitorCallback} after authentication
* results are known. Note that this happens asynchronously from (but shortly after)
* {@link #onAuthenticated(BiometricAuthenticator.Identifier, boolean, ArrayList)} and allows
* {@link CoexCoordinator} a chance to invoke/delay this event.
@@ -440,7 +440,7 @@
* Start authentication
*/
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
final @LockoutTracker.LockoutMode int lockoutMode =
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 1248c8b..e1f7e2a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -29,8 +29,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.log.BiometricLogger;
-import java.util.ArrayList;
-import java.util.List;
import java.util.NoSuchElementException;
/**
@@ -46,63 +44,6 @@
// Counter used to distinguish between ClientMonitor instances to help debugging.
private static int sCount = 0;
- /**
- * Interface that ClientMonitor holders should use to receive callbacks.
- */
- public interface Callback {
- /**
- * Invoked when the ClientMonitor operation has been started (e.g. reached the head of
- * the queue and becomes the current operation).
- *
- * @param clientMonitor Reference of the ClientMonitor that is starting.
- */
- default void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- }
-
- /**
- * Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous
- * (i.e. Authenticate, Enroll, Enumerate, Remove) and synchronous (i.e. generateChallenge,
- * revokeChallenge) so that a scheduler can process ClientMonitors regardless of their
- * implementation.
- *
- * @param clientMonitor Reference of the ClientMonitor that finished.
- * @param success True if the operation completed successfully.
- */
- default void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
- }
- }
-
- /** Holder for wrapping multiple handlers into a single Callback. */
- public static class CompositeCallback implements Callback {
- @NonNull
- private final List<Callback> mCallbacks;
-
- public CompositeCallback(@NonNull Callback... callbacks) {
- mCallbacks = new ArrayList<>();
-
- for (Callback callback : callbacks) {
- if (callback != null) {
- mCallbacks.add(callback);
- }
- }
- }
-
- @Override
- public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onClientStarted(clientMonitor);
- }
- }
-
- @Override
- public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
- boolean success) {
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).onClientFinished(clientMonitor, success);
- }
- }
- }
-
private final int mSequentialId;
@NonNull private final Context mContext;
private final int mTargetUserId;
@@ -120,7 +61,7 @@
// Use an empty callback by default since delayed operations can receive events
// before they are started and cause NPE in subclasses that access this field directly.
- @NonNull protected Callback mCallback = new Callback() {
+ @NonNull protected ClientMonitorCallback mCallback = new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
Slog.e(TAG, "mCallback onClientStarted: called before set (should not happen)");
@@ -134,18 +75,6 @@
};
/**
- * @return A ClientMonitorEnum constant defined in biometrics.proto
- */
- public abstract int getProtoEnum();
-
- /**
- * @return True if the ClientMonitor should cancel any current and pending interruptable clients
- */
- public boolean interruptsPrecedingClients() {
- return false;
- }
-
- /**
* @param context system_server context
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
@@ -189,11 +118,19 @@
}
}
+ /** A ClientMonitorEnum constant defined in biometrics.proto */
+ public abstract int getProtoEnum();
+
+ /** True if the ClientMonitor should cancel any current and pending interruptable clients. */
+ public boolean interruptsPrecedingClients() {
+ return false;
+ }
+
/**
* Starts the ClientMonitor's lifecycle.
* @param callback invoked when the operation is complete (succeeds, fails, etc)
*/
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
mCallback = wrapCallbackForStart(callback);
mCallback.onClientStarted(this);
}
@@ -204,7 +141,7 @@
* Returns the original callback unless overridden.
*/
@NonNull
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return callback;
}
@@ -329,7 +266,7 @@
}
@VisibleForTesting
- public Callback getCallback() {
+ public ClientMonitorCallback getCallback() {
return mCallback;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 39c5944..1a6da94 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -160,7 +160,7 @@
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
// starting the next client).
- private final BaseClientMonitor.Callback mInternalCallback = new BaseClientMonitor.Callback() {
+ private final ClientMonitorCallback mInternalCallback = new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
Slog.d(getTag(), "[Started] " + clientMonitor);
@@ -247,7 +247,7 @@
}
@VisibleForTesting
- public BaseClientMonitor.Callback getInternalCallback() {
+ public ClientMonitorCallback getInternalCallback() {
return mInternalCallback;
}
@@ -368,7 +368,7 @@
* @param clientCallback optional callback, invoked when the client state changes.
*/
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
- @Nullable BaseClientMonitor.Callback clientCallback) {
+ @Nullable ClientMonitorCallback clientCallback) {
// If the incoming operation should interrupt preceding clients, mark any interruptable
// pending clients as canceling. Once they reach the head of the queue, the scheduler will
// send ERROR_CANCELED and skip the operation.
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index e8b50d9..812ca8a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -65,7 +65,7 @@
protected static final int STATE_WAITING_FOR_COOKIE = 4;
/**
- * The {@link BaseClientMonitor.Callback} has been invoked and the client is finished.
+ * The {@link ClientMonitorCallback} has been invoked and the client is finished.
*/
protected static final int STATE_FINISHED = 5;
@@ -83,7 +83,7 @@
@NonNull
private final BaseClientMonitor mClientMonitor;
@Nullable
- private final BaseClientMonitor.Callback mClientCallback;
+ private final ClientMonitorCallback mClientCallback;
@OperationState
private int mState;
@VisibleForTesting
@@ -92,14 +92,14 @@
BiometricSchedulerOperation(
@NonNull BaseClientMonitor clientMonitor,
- @Nullable BaseClientMonitor.Callback callback
+ @Nullable ClientMonitorCallback callback
) {
this(clientMonitor, callback, STATE_WAITING_IN_QUEUE);
}
protected BiometricSchedulerOperation(
@NonNull BaseClientMonitor clientMonitor,
- @Nullable BaseClientMonitor.Callback callback,
+ @Nullable ClientMonitorCallback callback,
@OperationState int state
) {
mClientMonitor = clientMonitor;
@@ -139,7 +139,7 @@
* @param callback lifecycle callback
* @return if this operation started
*/
- public boolean start(@NonNull BaseClientMonitor.Callback callback) {
+ public boolean start(@NonNull ClientMonitorCallback callback) {
checkInState("start",
STATE_WAITING_IN_QUEUE,
STATE_WAITING_FOR_COOKIE,
@@ -159,7 +159,7 @@
* @param cookie cookie indicting the operation should begin
* @return if this operation started
*/
- public boolean startWithCookie(@NonNull BaseClientMonitor.Callback callback, int cookie) {
+ public boolean startWithCookie(@NonNull ClientMonitorCallback callback, int cookie) {
checkInState("start",
STATE_WAITING_IN_QUEUE,
STATE_WAITING_FOR_COOKIE,
@@ -173,8 +173,8 @@
return doStart(callback);
}
- private boolean doStart(@NonNull BaseClientMonitor.Callback callback) {
- final BaseClientMonitor.Callback cb = getWrappedCallback(callback);
+ private boolean doStart(@NonNull ClientMonitorCallback callback) {
+ final ClientMonitorCallback cb = getWrappedCallback(callback);
if (mState == STATE_WAITING_IN_QUEUE_CANCELING) {
Slog.d(TAG, "Operation marked for cancellation, cancelling now: " + this);
@@ -239,9 +239,9 @@
*
* @param handler handler to use for the cancellation watchdog
* @param callback lifecycle callback (only used if this operation hasn't started, otherwise
- * the callback used from {@link #start(BaseClientMonitor.Callback)} is used)
+ * the callback used from {@link #start(ClientMonitorCallback)} is used)
*/
- public void cancel(@NonNull Handler handler, @NonNull BaseClientMonitor.Callback callback) {
+ public void cancel(@NonNull Handler handler, @NonNull ClientMonitorCallback callback) {
checkNotInState("cancel", STATE_FINISHED);
final int currentState = mState;
@@ -270,14 +270,14 @@
}
@NonNull
- private BaseClientMonitor.Callback getWrappedCallback() {
+ private ClientMonitorCallback getWrappedCallback() {
return getWrappedCallback(null);
}
@NonNull
- private BaseClientMonitor.Callback getWrappedCallback(
- @Nullable BaseClientMonitor.Callback callback) {
- final BaseClientMonitor.Callback destroyCallback = new BaseClientMonitor.Callback() {
+ private ClientMonitorCallback getWrappedCallback(
+ @Nullable ClientMonitorCallback callback) {
+ final ClientMonitorCallback destroyCallback = new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
@@ -286,7 +286,7 @@
mState = STATE_FINISHED;
}
};
- return new BaseClientMonitor.CompositeCallback(destroyCallback, callback, mClientCallback);
+ return new ClientMonitorCompositeCallback(destroyCallback, callback, mClientCallback);
}
/** {@link BaseClientMonitor#getSensorId()}. */
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallback.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallback.java
new file mode 100644
index 0000000..8ea4ee9
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallback.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.biometrics.sensors;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface that ClientMonitor holders should use to receive callbacks.
+ */
+public interface ClientMonitorCallback {
+ /**
+ * Invoked when the ClientMonitor operation has been started (e.g. reached the head of
+ * the queue and becomes the current operation).
+ *
+ * @param clientMonitor Reference of the ClientMonitor that is starting.
+ */
+ default void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {}
+
+ /**
+ * Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous
+ * (i.e. Authenticate, Enroll, Enumerate, Remove) and synchronous (i.e. generateChallenge,
+ * revokeChallenge) so that a scheduler can process ClientMonitors regardless of their
+ * implementation.
+ *
+ * @param clientMonitor Reference of the ClientMonitor that finished.
+ * @param success True if the operation completed successfully.
+ */
+ default void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {}
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCompositeCallback.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCompositeCallback.java
new file mode 100644
index 0000000..b82f5fa
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCompositeCallback.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.biometrics.sensors;
+
+import android.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Holder for wrapping multiple handlers into a single Callback. */
+public class ClientMonitorCompositeCallback implements ClientMonitorCallback {
+ @NonNull
+ private final List<ClientMonitorCallback> mCallbacks;
+
+ public ClientMonitorCompositeCallback(@NonNull ClientMonitorCallback... callbacks) {
+ mCallbacks = new ArrayList<>();
+
+ for (ClientMonitorCallback callback : callbacks) {
+ if (callback != null) {
+ mCallbacks.add(callback);
+ }
+ }
+ }
+
+ @Override
+ public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onClientStarted(clientMonitor);
+ }
+ }
+
+ @Override
+ public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+ boolean success) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).onClientFinished(clientMonitor, success);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index c83323a..3b7adc1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -98,7 +98,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
if (hasReachedEnrollmentLimit()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java
index c2f909b..3060f30 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java
@@ -23,7 +23,7 @@
/**
* Callers should typically check this after
- * {@link BaseClientMonitor.Callback#onClientFinished(BaseClientMonitor, boolean)}
+ * {@link ClientMonitorCallback#onClientFinished(BaseClientMonitor, boolean)}
*
* @return true if the user has gone from:
* 1) none-enrolled --> enrolled
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 3d74f36..6fb6d08 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -47,7 +47,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
index 63cd412..c8830f8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
@@ -45,7 +45,7 @@
/**
* Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
* If such a problem is detected, the scheduler will not invoke
- * {@link #start(Callback)}.
+ * {@link #start(ClientMonitorCallback)}.
*/
public abstract void unableToStart();
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index 82a8437..0636893 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -64,7 +64,7 @@
private final boolean mHasEnrollmentsBeforeStarting;
private BaseClientMonitor mCurrentTask;
- private final Callback mEnumerateCallback = new Callback() {
+ private final ClientMonitorCallback mEnumerateCallback = new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
@@ -90,7 +90,7 @@
}
};
- private final Callback mRemoveCallback = new Callback() {
+ private final ClientMonitorCallback mRemoveCallback = new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
Slog.d(TAG, "Remove onClientFinished: " + clientMonitor + ", success: " + success);
@@ -139,7 +139,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
// Start enumeration. Removal will start if necessary, when enumeration is completed.
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index ced464e..05ea19a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -72,7 +72,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
// The biometric template ids will be removed when we get confirmation from the HAL
diff --git a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java b/services/core/java/com/android/server/biometrics/sensors/Interruptable.java
index d5093c75..4f645ef 100644
--- a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java
+++ b/services/core/java/com/android/server/biometrics/sensors/Interruptable.java
@@ -29,15 +29,15 @@
/**
* Notifies the client that it needs to finish before
- * {@link BaseClientMonitor#start(BaseClientMonitor.Callback)} was invoked. This usually happens
+ * {@link BaseClientMonitor#start(ClientMonitorCallback)} was invoked. This usually happens
* if the client is still waiting in the pending queue and got notified that a subsequent
* operation is preempting it.
*
* This method must invoke
- * {@link BaseClientMonitor.Callback#onClientFinished(BaseClientMonitor, boolean)} on the
+ * {@link ClientMonitorCallback#onClientFinished(BaseClientMonitor, boolean)} on the
* given callback (with success).
*
* @param callback invoked when the operation is completed.
*/
- void cancelWithoutStarting(@NonNull BaseClientMonitor.Callback callback);
+ void cancelWithoutStarting(@NonNull ClientMonitorCallback callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
index cede4a7..ee6bb0f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
@@ -62,7 +62,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
index 5ba1b00..b2661a2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
@@ -84,7 +84,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mUtils.setInvalidationInProgress(getContext(), getTargetUserId(), true /* inProgress */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index 2a6677e..e79819b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -59,7 +58,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
// The biometric template ids will be removed when we get confirmation from the HAL
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index 1edf5af..21a6ddf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -38,7 +38,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 603cc22..4f90020 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -56,7 +56,7 @@
@NonNull private final UserSwitchCallback mUserSwitchCallback;
@Nullable private StopUserClient<?> mStopUserClient;
- private class ClientFinishedCallback implements BaseClientMonitor.Callback {
+ private class ClientFinishedCallback implements ClientMonitorCallback {
private final BaseClientMonitor mOwner;
ClientFinishedCallback(BaseClientMonitor owner) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 77e431c..1e9b72b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -29,7 +29,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -137,7 +137,7 @@
void startPreparedClient(int sensorId, int cookie);
void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback);
+ @Nullable ClientMonitorCallback callback);
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 66b942b..8998269 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -35,6 +35,7 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.face.FaceUtils;
import java.util.HashSet;
@@ -221,7 +222,7 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
Slog.d(TAG, "cleanupInternalState: " + userId);
- mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+ mProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 757a52cb..dc21a04f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -39,7 +39,9 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -97,15 +99,15 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mState = STATE_STARTED;
}
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index 2158dfe..72a20db07 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -30,6 +30,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.DetectionConsumer;
@@ -58,7 +59,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index b5f89b4..5c57dbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -41,7 +41,9 @@
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.face.FaceService;
import com.android.server.biometrics.sensors.face.FaceUtils;
@@ -67,8 +69,8 @@
private final int mMaxTemplatesPerUser;
private final boolean mDebugConsent;
- private final BaseClientMonitor.Callback mPreviewHandleDeleterCallback =
- new BaseClientMonitor.Callback() {
+ private final ClientMonitorCallback mPreviewHandleDeleterCallback =
+ new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
}
@@ -101,7 +103,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
BiometricNotificationUtils.cancelReEnrollNotification(getContext());
@@ -109,8 +111,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(mPreviewHandleDeleterCallback,
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(mPreviewHandleDeleterCallback,
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
index af826c2..584b58c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -24,6 +24,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.Map;
@@ -48,7 +49,7 @@
// Nothing to do here
}
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
index 315ede8b..acf5720 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
@@ -29,6 +29,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -60,7 +61,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index ae507ab..9d7a552 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -49,6 +49,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -217,7 +218,7 @@
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
- BaseClientMonitor.Callback callback) {
+ ClientMonitorCallback callback) {
if (!mSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
@@ -341,7 +342,7 @@
opPackageName, id, FaceUtils.getInstance(sensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
debugConsent);
- scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
+ scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
@@ -511,7 +512,7 @@
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback) {
+ @Nullable ClientMonitorCallback callback) {
mHandler.post(() -> {
final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
final FaceInternalCleanupClient client =
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index 1e1b532..fd44c5c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -27,6 +27,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -64,7 +65,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
index 4515d04..ee6982a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
@@ -28,6 +28,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -65,7 +66,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
index 2b5f495..4a3da0d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.StartUserClient;
public class FaceStartUserClient extends StartUserClient<IFace, ISession> {
@@ -43,7 +44,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
index 06328e3..88b9235 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
@@ -24,6 +24,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.StopUserClient;
public class FaceStopUserClient extends StopUserClient<ISession> {
@@ -36,7 +37,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index b45578b..e7483b3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -32,6 +32,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.face.FaceUtils;
import java.util.ArrayList;
@@ -197,7 +198,7 @@
public void cleanupInternalState(int userId) {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
- mFace10.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+ mFace10.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index e957794..9a52db1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -60,6 +60,7 @@
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.ErrorConsumer;
@@ -534,7 +535,7 @@
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
opPackageName, mSensorId, sSystemClock.millis());
mGeneratedChallengeCache = client;
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
if (client != clientMonitor) {
@@ -562,7 +563,7 @@
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
mLazyDaemon, token, userId, opPackageName, mSensorId);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
@@ -591,7 +592,7 @@
opPackageName, id, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, mSensorId);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
@@ -742,7 +743,7 @@
final int faceId = faces.get(0).getBiometricId();
final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, mLazyDaemon,
token, listener, userId, opPackageName, mSensorId, feature, faceId);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientFinished(
@NonNull BaseClientMonitor clientMonitor, boolean success) {
@@ -760,7 +761,7 @@
}
private void scheduleInternalCleanup(int userId,
- @Nullable BaseClientMonitor.Callback callback) {
+ @Nullable ClientMonitorCallback callback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -774,7 +775,7 @@
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback) {
+ @Nullable ClientMonitorCallback callback) {
scheduleInternalCleanup(userId, callback);
}
@@ -890,7 +891,7 @@
final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId,
hasEnrolled, mAuthenticatorIds);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 80faf3e..1e0e799 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -34,7 +34,9 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.face.UsageStats;
@@ -87,15 +89,15 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mState = STATE_STARTED;
}
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 5c69d6f..8068e14 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -33,7 +33,9 @@
import com.android.internal.R;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import java.util.ArrayList;
@@ -69,8 +71,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
index f418104..e29a192 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
@@ -25,6 +25,7 @@
import android.util.Slog;
import com.android.internal.util.Preconditions;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.GenerateChallengeClient;
@@ -39,7 +40,7 @@
private static final String TAG = "FaceGenerateChallengeClient";
static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
- private static final Callback EMPTY_CALLBACK = new Callback() {
+ private static final ClientMonitorCallback EMPTY_CALLBACK = new ClientMonitorCallback() {
};
private final long mCreatedAt;
@@ -94,7 +95,7 @@
}
private void sendChallengeResult(@NonNull ClientMonitorCallbackConverter receiver,
- @NonNull Callback ownerCallback) {
+ @NonNull ClientMonitorCallback ownerCallback) {
Preconditions.checkState(mChallengeResult != null, "result not available");
try {
receiver.onChallengeGenerated(getSensorId(), getTargetUserId(), mChallengeResult);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index 7821601..0a9d96d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -28,6 +28,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -66,7 +67,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index 9d977d6..ee01c43 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -24,6 +24,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.ArrayList;
@@ -57,7 +58,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
index cc3d8f0..ee28f7b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
@@ -26,6 +26,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -71,7 +72,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 5343d0d..8ee8ce5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -25,6 +25,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.io.File;
@@ -49,7 +50,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
index be0e6ed..04fd534 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
@@ -31,6 +31,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.EnrollmentModifier;
@@ -39,7 +40,7 @@
/**
* A callback for receiving notifications about changes in fingerprint state.
*/
-public class FingerprintStateCallback implements BaseClientMonitor.Callback {
+public class FingerprintStateCallback implements ClientMonitorCallback {
@NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
mFingerprintStateListeners = new CopyOnWriteArrayList<>();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 535705c..0bdc4eb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -30,7 +30,7 @@
import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -121,7 +121,7 @@
@NonNull String opPackageName);
void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback);
+ @Nullable ClientMonitorCallback callback);
boolean isHardwareDetected(int sensorId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 2b50b96..b29fbb6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -32,6 +32,7 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
@@ -204,7 +205,7 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
Slog.d(TAG, "cleanupInternalState: " + userId);
- mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+ mProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 96f4853..f3d0121 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -37,7 +37,9 @@
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -86,7 +88,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
if (mSensorProps.isAnyUdfpsType()) {
@@ -99,8 +101,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(mALSProbeCallback, callback);
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(mALSProbeCallback, callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index ac3ce89..1f0482d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -30,6 +30,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.DetectionConsumer;
import com.android.server.biometrics.sensors.SensorOverlays;
@@ -61,7 +62,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index e3f26df..169c3eb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -37,7 +37,9 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
@@ -82,8 +84,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
index ed2345e..52bd234 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
@@ -24,6 +24,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.Map;
@@ -48,7 +49,7 @@
// Nothing to do here
}
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index eb16c76..efc9304 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -55,7 +55,9 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
@@ -248,7 +250,7 @@
}
private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
- BaseClientMonitor.Callback callback) {
+ ClientMonitorCallback callback) {
if (!mSensors.contains(sensorId)) {
throw new IllegalStateException("Unable to schedule client: " + client
+ " for sensor: " + sensorId);
@@ -361,7 +363,7 @@
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
mSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController, maxTemplatesPerUser, enrollReason);
- scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
+ scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -484,7 +486,7 @@
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback) {
+ @Nullable ClientMonitorCallback callback) {
mHandler.post(() -> {
final List<Fingerprint> enrolledList = getEnrolledFingerprints(sensorId, userId);
final FingerprintInternalCleanupClient client =
@@ -493,7 +495,7 @@
mContext.getOpPackageName(), sensorId, enrolledList,
FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client, new BaseClientMonitor.CompositeCallback(callback,
+ scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(callback,
mFingerprintStateCallback));
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 878ef46..ee8d170 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -27,6 +27,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -64,7 +65,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
index ee81620..9f11df6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.StartUserClient;
public class FingerprintStartUserClient extends StartUserClient<IFingerprint, ISession> {
@@ -44,7 +45,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
index 7055d65..9d38145 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
@@ -24,6 +24,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.StopUserClient;
public class FingerprintStopUserClient extends StopUserClient<ISession> {
@@ -36,7 +37,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 79c6b1b3..033855f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -31,6 +31,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
@@ -201,7 +202,7 @@
public void cleanupInternalState(int userId) {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
- mFingerprint21.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+ mFingerprint21.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 6feb5fa..f160dff 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -62,7 +62,9 @@
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -492,7 +494,7 @@
new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
mContext.getOpPackageName(), mSensorProperties.sensorId,
this::getCurrentUser, hasEnrolled, mAuthenticatorIds, force);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
@@ -577,7 +579,7 @@
FingerprintUtils.getLegacyInstance(mSensorId), ENROLL_TIMEOUT_SEC,
mSensorProperties.sensorId, mUdfpsOverlayController, mSidefpsController,
enrollReason);
- mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
mFingerprintStateCallback.onClientStarted(clientMonitor);
@@ -699,7 +701,7 @@
}
private void scheduleInternalCleanup(int userId,
- @Nullable BaseClientMonitor.Callback callback) {
+ @Nullable ClientMonitorCallback callback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -715,8 +717,8 @@
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
- @Nullable BaseClientMonitor.Callback callback) {
- scheduleInternalCleanup(userId, new BaseClientMonitor.CompositeCallback(callback,
+ @Nullable ClientMonitorCallback callback) {
+ scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback,
mFingerprintStateCallback));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index d9b290f..87d47c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -36,7 +36,9 @@
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
@@ -86,7 +88,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
if (mSensorProps.isAnyUdfpsType()) {
@@ -99,8 +101,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(mALSProbeCallback, callback);
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(mALSProbeCallback, callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index f1dec66..9137212 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -32,6 +32,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.SensorOverlays;
@@ -82,7 +83,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index dd92e3e..82b046d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -33,7 +33,9 @@
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
@@ -75,8 +77,8 @@
@NonNull
@Override
- protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(
+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
+ return new ClientMonitorCompositeCallback(
getLogger().createALSCallback(true /* startWithClient */), callback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
index a39f4f8..ed28e3f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
@@ -22,6 +22,7 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
/**
* Clears lockout, which is handled in the framework (and not the HAL) for the
@@ -40,7 +41,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mLockoutTracker.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
getTargetUserId());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index a2c1892..d317984 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -27,6 +27,7 @@
import android.util.Slog;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.io.File;
@@ -62,7 +63,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
if (mCurrentUserId.get() == getTargetUserId() && !mForceUpdateAuthenticatorId) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 06f56c9..4da26f6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -97,7 +97,6 @@
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IInterface;
import android.os.LocaleList;
import android.os.Message;
import android.os.Parcel;
@@ -220,13 +219,8 @@
}
private static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
- private static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
private static final int MSG_SHOW_IM_CONFIG = 3;
- private static final int MSG_UNBIND_INPUT = 1000;
- private static final int MSG_BIND_INPUT = 1010;
- private static final int MSG_SHOW_SOFT_INPUT = 1020;
- private static final int MSG_HIDE_SOFT_INPUT = 1030;
private static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
private static final int MSG_INITIALIZE_IME = 1040;
private static final int MSG_CREATE_SESSION = 1050;
@@ -785,7 +779,7 @@
final int mFocusedWindowSoftInputMode;
@SoftInputShowHideReason
final int mReason;
- // The timing of handling MSG_SHOW_SOFT_INPUT or MSG_HIDE_SOFT_INPUT.
+ // The timing of handling showCurrentInputLocked() or hideCurrentInputLocked().
final long mTimestamp;
final long mWallTime;
final boolean mInFullscreenMode;
@@ -1575,7 +1569,7 @@
mHandler.removeCallbacks(mUserSwitchHandlerTask);
}
// Hide soft input before user switch task since switch task may block main handler a while
- // and delayed the MSG_HIDE_SOFT_INPUT.
+ // and delayed the hideCurrentInputLocked().
hideCurrentInputLocked(
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
@@ -2203,8 +2197,11 @@
mBoundToMethod = false;
IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null) {
- executeOrSendMessage(curMethod, mCaller.obtainMessageO(
- MSG_UNBIND_INPUT, curMethod));
+ try {
+ curMethod.unbindInput();
+ } catch (RemoteException e) {
+ // There is nothing interesting about the method dying.
+ }
}
}
mCurClient = null;
@@ -2216,8 +2213,24 @@
}
}
- private void executeOrSendMessage(IInterface target, Message msg) {
+ // TODO(b/215609403): This method will be removed soon!
+ private void executeOrSendMessage(IInputMethod target, Message msg) {
+ if (target.asBinder() instanceof Binder) {
+ throw new UnsupportedOperationException(
+ "InputMethodService is not supported to run in the system_server");
+ }
+ handleMessage(msg);
+ msg.recycle();
+ }
+
+ private void executeOrSendMessage(IInputMethodClient target, Message msg) {
if (target.asBinder() instanceof Binder) {
+ // This is supposed to be emulating the one-way semantics when the IME client is
+ // system_server itself, which has not been explicitly prohibited so far while we have
+ // never ever officially supported such a use case...
+ // We probably should create a simple wrapper of IInputMethodClient as the first step
+ // to get rid of executeOrSendMessage() then should prohibit system_server to be the
+ // IME client for long term.
mCaller.sendMessage(msg);
} else {
handleMessage(msg);
@@ -2234,8 +2247,11 @@
mBoundToMethod = false;
IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null) {
- executeOrSendMessage(curMethod, mCaller.obtainMessageO(
- MSG_UNBIND_INPUT, curMethod));
+ try {
+ curMethod.unbindInput();
+ } catch (RemoteException e) {
+ // There is nothing interesting about the method dying.
+ }
}
}
@@ -2285,8 +2301,10 @@
InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
if (!mBoundToMethod) {
IInputMethod curMethod = getCurMethodLocked();
- executeOrSendMessage(curMethod, mCaller.obtainMessageOO(
- MSG_BIND_INPUT, curMethod, mCurClient.binding));
+ try {
+ curMethod.bindInput(mCurClient.binding);
+ } catch (RemoteException e) {
+ }
mBoundToMethod = true;
}
@@ -3112,18 +3130,25 @@
}
mBindingController.setCurrentMethodVisible();
- if (getCurMethodLocked() != null) {
+ final IInputMethod curMethod = getCurMethodLocked();
+ if (curMethod != null) {
// create a placeholder token for IMS so that IMS cannot inject windows into client app.
Binder showInputToken = new Binder();
mShowRequestWindowMap.put(showInputToken, windowToken);
- IInputMethod curMethod = getCurMethodLocked();
- executeOrSendMessage(curMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT,
- getImeShowFlagsLocked(), reason, curMethod, resultReceiver,
- showInputToken));
+ final int showFlags = getImeShowFlagsLocked();
+ try {
+ if (DEBUG) {
+ Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
+ + ", " + showFlags + ", " + resultReceiver + ") for reason: "
+ + InputMethodDebug.softInputDisplayReasonToString(reason));
+ }
+ curMethod.showSoftInput(showInputToken, showFlags, resultReceiver);
+ onShowHideSoftInputRequested(true /* show */, windowToken, reason);
+ } catch (RemoteException e) {
+ }
mInputShown = true;
return true;
}
-
return false;
}
@@ -3202,8 +3227,16 @@
// delivered to the IME process as an IPC. Hence the inconsistency between
// IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
// the final state.
- executeOrSendMessage(curMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
- reason, curMethod, resultReceiver, hideInputToken));
+ if (DEBUG) {
+ Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
+ + ", " + resultReceiver + ") for reason: "
+ + InputMethodDebug.softInputDisplayReasonToString(reason));
+ }
+ try {
+ curMethod.hideSoftInput(hideInputToken, 0 /* flags */, resultReceiver);
+ onShowHideSoftInputRequested(false /* show */, windowToken, reason);
+ } catch (RemoteException e) {
+ }
res = true;
} else {
res = false;
@@ -3679,8 +3712,7 @@
if (!calledFromValidUserLocked()) {
return;
}
- executeOrSendMessage(getCurMethodLocked(), mCaller.obtainMessageO(
- MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
+ showInputMethodAndSubtypeEnabler(inputMethodId);
}
}
@@ -4203,69 +4235,12 @@
mMenuController.showInputMethodMenu(showAuxSubtypes, displayId);
return true;
- case MSG_SHOW_IM_SUBTYPE_ENABLER:
- showInputMethodAndSubtypeEnabler((String)msg.obj);
- return true;
-
case MSG_SHOW_IM_CONFIG:
showConfigureInputMethods();
return true;
// ---------------------------------------------------------
- case MSG_UNBIND_INPUT:
- try {
- ((IInputMethod)msg.obj).unbindInput();
- } catch (RemoteException e) {
- // There is nothing interesting about the method dying.
- }
- return true;
- case MSG_BIND_INPUT:
- args = (SomeArgs)msg.obj;
- try {
- ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
- } catch (RemoteException e) {
- }
- args.recycle();
- return true;
- case MSG_SHOW_SOFT_INPUT:
- args = (SomeArgs) msg.obj;
- try {
- final @SoftInputShowHideReason int reason = msg.arg2;
- if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
- + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: "
- + InputMethodDebug.softInputDisplayReasonToString(reason));
- final IBinder token = (IBinder) args.arg3;
- ((IInputMethod) args.arg1).showSoftInput(
- token, msg.arg1 /* flags */, (ResultReceiver) args.arg2);
- final IBinder requestToken;
- synchronized (ImfLock.class) {
- requestToken = mShowRequestWindowMap.get(token);
- onShowHideSoftInputRequested(true /* show */, requestToken, reason);
- }
- } catch (RemoteException e) {
- }
- args.recycle();
- return true;
- case MSG_HIDE_SOFT_INPUT:
- args = (SomeArgs) msg.obj;
- try {
- final @SoftInputShowHideReason int reason = msg.arg1;
- if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
- + args.arg3 + ", " + args.arg2 + ") for reason: "
- + InputMethodDebug.softInputDisplayReasonToString(reason));
- final IBinder token = (IBinder) args.arg3;
- ((IInputMethod)args.arg1).hideSoftInput(
- token, 0 /* flags */, (ResultReceiver) args.arg2);
- final IBinder requestToken;
- synchronized (ImfLock.class) {
- requestToken = mHideRequestWindowMap.get(token);
- onShowHideSoftInputRequested(false /* show */, requestToken, reason);
- }
- } catch (RemoteException e) {
- }
- args.recycle();
- return true;
case MSG_HIDE_CURRENT_INPUT_METHOD:
synchronized (ImfLock.class) {
final @SoftInputShowHideReason int reason = (int) msg.obj;
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index ffc1aed4..91de9e5 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -344,10 +344,19 @@
}
private void addActiveRoute(BluetoothRouteInfo btRoute) {
+ if (btRoute == null) {
+ if (DEBUG) {
+ Log.d(TAG, " btRoute is null");
+ }
+ return;
+ }
if (DEBUG) {
Log.d(TAG, "Adding active route: " + btRoute.route);
}
- if (btRoute == null || mActiveRoutes.contains(btRoute)) {
+ if (mActiveRoutes.contains(btRoute)) {
+ if (DEBUG) {
+ Log.d(TAG, " btRoute is already added.");
+ }
return;
}
setRouteConnectionState(btRoute, STATE_CONNECTED);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 6f10a6b..2e9ad50 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -45,6 +45,7 @@
import android.sysprop.ApexProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.PrintWriterPrinter;
import android.util.Singleton;
import android.util.Slog;
import android.util.SparseArray;
@@ -1164,6 +1165,10 @@
ipw.println("Path: " + pi.applicationInfo.sourceDir);
ipw.println("IsActive: " + isActive(pi));
ipw.println("IsFactory: " + isFactory(pi));
+ ipw.println("ApplicationInfo: ");
+ ipw.increaseIndent();
+ pi.applicationInfo.dump(new PrintWriterPrinter(ipw), "");
+ ipw.decreaseIndent();
ipw.decreaseIndent();
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1cfcdf51..8e16835 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -558,9 +558,9 @@
}
@Override
- public void selfRevokePermissions(@NonNull String packageName,
+ public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
- mPermissionManagerServiceImpl.selfRevokePermissions(packageName, permissions);
+ mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 981fd8e..d639f7d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1592,7 +1592,7 @@
}
@Override
- public void selfRevokePermissions(String packageName, List<String> permissions) {
+ public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
final int callingUid = Binder.getCallingUid();
int callingUserId = UserHandle.getUserId(callingUid);
int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
@@ -1607,7 +1607,7 @@
+ permName + " because it does not hold that permission");
}
}
- mPermissionControllerManager.selfRevokePermissions(packageName, permissions);
+ mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
}
private boolean mayManageRolePermission(int uid) {
@@ -3181,9 +3181,13 @@
ps.updatePermissionFlags(bp, PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
| FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED);
- // TODO(b/205888750): remove revoke once propagated through droidfood
- if (ps.isPermissionGranted(newPerm)) {
+ // TODO(b/205888750): remove if/else block once propagated through droidfood
+ if (ps.isPermissionGranted(newPerm)
+ && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
ps.revokePermission(bp);
+ } else if (!ps.isPermissionGranted(newPerm)
+ && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
+ ps.grantPermission(bp);
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index c582f9e..b558e3d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -344,7 +344,7 @@
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*/
- void selfRevokePermissions(String packageName, List<String> permissions);
+ void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
/**
* Get whether you should show UI with rationale for requesting a permission. You should do this
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 17f5566..0edd06a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -22,6 +22,7 @@
import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
import static android.app.StatusBarManager.NavBarModeOverride;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
import android.Manifest;
import android.annotation.NonNull;
@@ -38,6 +39,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.om.IOverlayManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
@@ -60,6 +62,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.Settings;
@@ -79,6 +82,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.os.TransferPipe;
import com.android.internal.statusbar.IAddTileResultCallback;
@@ -154,6 +158,8 @@
private final ArrayMap<String, Long> mCurrentRequestAddTilePackages = new ArrayMap<>();
private static final long REQUEST_TIME_OUT = TimeUnit.MINUTES.toNanos(5);
+ private IOverlayManager mOverlayManager;
+
private class DeathRecipient implements IBinder.DeathRecipient {
public void binderDied() {
mBar.asBinder().unlinkToDeath(this,0);
@@ -256,6 +262,18 @@
mTileRequestTracker = new TileRequestTracker(mContext);
}
+ private IOverlayManager getOverlayManager() {
+ // No need to synchronize; worst-case scenario it will be fetched twice.
+ if (mOverlayManager == null) {
+ mOverlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
+ if (mOverlayManager == null) {
+ Slog.w("StatusBarManager", "warning: no OVERLAY_SERVICE");
+ }
+ }
+ return mOverlayManager;
+ }
+
@Override
public void onDisplayAdded(int displayId) {}
@@ -1296,6 +1314,11 @@
});
}
+ @VisibleForTesting
+ void registerOverlayManager(IOverlayManager overlayManager) {
+ mOverlayManager = overlayManager;
+ }
+
/**
* @param clearNotificationEffects whether to consider notifications as "shown" and stop
* LED, vibration, and ringing
@@ -1869,6 +1892,14 @@
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.NAV_BAR_KIDS_MODE, navBarModeOverride, userId);
+
+ IOverlayManager overlayManager = getOverlayManager();
+ if (overlayManager != null && navBarModeOverride == NAV_BAR_MODE_OVERRIDE_KIDS
+ && isPackageSupported(NAV_BAR_MODE_3BUTTON_OVERLAY)) {
+ overlayManager.setEnabledExclusiveInCategory(NAV_BAR_MODE_3BUTTON_OVERLAY, userId);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
} finally {
Binder.restoreCallingIdentity(userIdentity);
}
@@ -1896,6 +1927,21 @@
return navBarKidsMode;
}
+ private boolean isPackageSupported(String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+ try {
+ return mContext.getPackageManager().getPackageInfo(packageName,
+ PackageManager.PackageInfoFlags.of(0)) != null;
+ } catch (PackageManager.NameNotFoundException ignored) {
+ if (SPEW) {
+ Slog.d(TAG, "Package not found: " + packageName);
+ }
+ }
+ return false;
+ }
+
/** @hide */
public void passThroughShellCommand(String[] args, FileDescriptor fd) {
enforceStatusBarOrShell();
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 3093509..c0207f0 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -37,6 +37,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.DataUnit;
@@ -255,11 +256,14 @@
private void checkHigh() {
final StorageManager storage = getContext().getSystemService(StorageManager.class);
// Check every mounted private volume to see if they're under the high storage threshold
- // which is StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space
+ // which is storageThresholdPercentHigh of total space
+ final int storageThresholdPercentHigh = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH_KEY,
+ StorageManager.DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final File file = vol.getPath();
- if (file.getUsableSpace() < file.getTotalSpace()
- * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
+ if (file.getUsableSpace() < file.getTotalSpace() * storageThresholdPercentHigh / 100) {
final PackageManagerService pms = (PackageManagerService) ServiceManager
.getService("package");
try {
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
similarity index 98%
rename from services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
rename to services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 6058d88..35cc43f 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -34,15 +34,15 @@
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
-import android.media.tv.interactive.ITvIAppManager;
import android.media.tv.interactive.ITvInteractiveAppClient;
+import android.media.tv.interactive.ITvInteractiveAppManager;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
import android.media.tv.interactive.ITvInteractiveAppService;
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
-import android.media.tv.interactive.TvIAppService;
import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -79,9 +79,9 @@
/**
* This class provides a system service that manages interactive TV applications.
*/
-public class TvIAppManagerService extends SystemService {
+public class TvInteractiveAppManagerService extends SystemService {
private static final boolean DEBUG = false;
- private static final String TAG = "TvIAppManagerService";
+ private static final String TAG = "TvInteractiveAppManagerService";
// A global lock.
private final Object mLock = new Object();
private final Context mContext;
@@ -106,7 +106,7 @@
*
* @param context The system server context.
*/
- public TvIAppManagerService(Context context) {
+ public TvInteractiveAppManagerService(Context context) {
super(context);
mContext = context;
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
@@ -122,7 +122,7 @@
}
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServicesAsUser(
- new Intent(TvIAppService.SERVICE_INTERFACE),
+ new Intent(TvInteractiveAppService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
@@ -256,15 +256,16 @@
@GuardedBy("mLock")
private void notifyStateChangedLocked(
- UserState userState, String iAppServiceId, int type, int state) {
+ UserState userState, String iAppServiceId, int type, int state, int err) {
if (DEBUG) {
Slog.d(TAG, "notifyRteStateChanged(iAppServiceId="
- + iAppServiceId + ", type=" + type + ", state=" + state + ")");
+ + iAppServiceId + ", type=" + type + ", state=" + state + ", err=" + err + ")");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- userState.mCallbacks.getBroadcastItem(i).onStateChanged(iAppServiceId, type, state);
+ userState.mCallbacks.getBroadcastItem(i)
+ .onStateChanged(iAppServiceId, type, state, err);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report RTE state changed", e);
}
@@ -287,7 +288,7 @@
if (DEBUG) {
Slogf.d(TAG, "onStart");
}
- publishBinderService(Context.TV_IAPP_SERVICE, new BinderService());
+ publishBinderService(Context.TV_INTERACTIVE_APP_SERVICE, new BinderService());
}
@Override
@@ -628,7 +629,7 @@
return session;
}
- private final class BinderService extends ITvIAppManager.Stub {
+ private final class BinderService extends ITvInteractiveAppManager.Stub {
@Override
public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
@@ -1361,7 +1362,7 @@
}
} finally {
if (surface != null) {
- // surface is not used in TvIAppManagerService.
+ // surface is not used in TvInteractiveAppManagerService.
surface.release();
}
Binder.restoreCallingIdentity(identity);
@@ -1678,7 +1679,7 @@
}
Intent i =
- new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
+ new Intent(TvInteractiveAppService.SERVICE_INTERFACE).setComponent(component);
serviceState.mBound = mContext.bindServiceAsUser(
i, serviceState.mConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
@@ -1866,6 +1867,16 @@
ServiceState serviceState = userState.mServiceStateMap.get(mComponent);
serviceState.mService = ITvInteractiveAppService.Stub.asInterface(service);
+ // Register a callback, if we need to.
+ if (serviceState.mCallback == null) {
+ serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
+ try {
+ serviceState.mService.registerCallback(serviceState.mCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in registerCallback", e);
+ }
+ }
+
if (serviceState.mPendingPrepare) {
final long identity = Binder.clearCallingIdentity();
try {
@@ -1968,14 +1979,14 @@
}
@Override
- public void onStateChanged(int type, int state) {
+ public void onStateChanged(int type, int state, int error) {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
String iAppServiceId = serviceState.mIAppServiceId;
UserState userState = getUserStateLocked(mUserId);
- notifyStateChangedLocked(userState, iAppServiceId, type, state);
+ notifyStateChangedLocked(userState, iAppServiceId, type, state, error);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2072,7 +2083,7 @@
@Override
public void onCommandRequest(
- @TvIAppService.InteractiveAppServiceCommandType String cmdType,
+ @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
synchronized (mLock) {
if (DEBUG) {
@@ -2210,16 +2221,16 @@
}
@Override
- public void onSessionStateChanged(int state) {
+ public void onSessionStateChanged(int state, int err) {
synchronized (mLock) {
if (DEBUG) {
- Slogf.d(TAG, "onSessionStateChanged (state=" + state + ")");
+ Slogf.d(TAG, "onSessionStateChanged (state=" + state + ", err=" + err + ")");
}
if (mSessionState.mSession == null || mSessionState.mClient == null) {
return;
}
try {
- mSessionState.mClient.onSessionStateChanged(state, mSessionState.mSeq);
+ mSessionState.mClient.onSessionStateChanged(state, err, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onSessionStateChanged", e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ddd624d..ed9dcef 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -221,10 +221,10 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationRunner;
-import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
+import android.window.BackNavigationInfo;
import android.window.IWindowOrganizerController;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.TaskSnapshot;
@@ -458,7 +458,7 @@
private final ClientLifecycleManager mLifecycleManager;
@Nullable
- private final BackGestureController mBackGestureController;
+ private final BackNavigationController mBackNavigationController;
private TaskChangeNotificationController mTaskChangeNotificationController;
/** The controller for all operations related to locktask. */
@@ -836,8 +836,6 @@
mSystemThread = ActivityThread.currentActivityThread();
mUiContext = mSystemThread.getSystemUiContext();
mLifecycleManager = new ClientLifecycleManager();
- mBackGestureController = BackGestureController.isEnabled() ? new BackGestureController()
- : null;
mVisibleActivityProcessTracker = new VisibleActivityProcessTracker(this);
mInternal = new LocalService();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
@@ -845,6 +843,8 @@
mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
mTaskFragmentOrganizerController =
mWindowOrganizerController.mTaskFragmentOrganizerController;
+ mBackNavigationController = BackNavigationController.isEnabled()
+ ? new BackNavigationController() : null;
}
public void onSystemReady() {
@@ -1022,6 +1022,9 @@
mLockTaskController.setWindowManager(wm);
mTaskSupervisor.setWindowManager(wm);
mRootWindowContainer.setWindowManager(wm);
+ if (mBackNavigationController != null) {
+ mBackNavigationController.setTaskSnapshotController(wm.mTaskSnapshotController);
+ }
}
}
@@ -1768,11 +1771,13 @@
}
@Override
- public void startBackPreview(IRemoteAnimationRunner runner) {
- if (mBackGestureController == null) {
- return;
+ public BackNavigationInfo startBackNavigation() {
+ mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "startBackNavigation()");
+ if (mBackNavigationController == null) {
+ return null;
}
- mBackGestureController.startBackPreview();
+ return mBackNavigationController.startBackNavigation(getTopDisplayFocusedRootTask());
}
/**
diff --git a/services/core/java/com/android/server/wm/BackGestureController.java b/services/core/java/com/android/server/wm/BackGestureController.java
deleted file mode 100644
index f8f6254..0000000
--- a/services/core/java/com/android/server/wm/BackGestureController.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2021 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;
-
-import android.os.SystemProperties;
-
-/**
- * Controller to handle actions related to the back gesture on the server side.
- */
-public class BackGestureController {
-
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
-
- public static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
- }
-
- /**
- * Start a remote animation the back gesture.
- */
- public void startBackPreview() {
- }
-}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
new file mode 100644
index 0000000..a8779fa
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.hardware.HardwareBuffer;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.window.BackNavigationInfo;
+import android.window.TaskSnapshot;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+
+/**
+ * Controller to handle actions related to the back gesture on the server side.
+ */
+class BackNavigationController {
+
+ private static final String TAG = "BackNavigationController";
+ private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+
+ @Nullable
+ private TaskSnapshotController mTaskSnapshotController;
+
+ /**
+ * Returns true if the back predictability feature is enabled
+ */
+ static boolean isEnabled() {
+ return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ }
+
+ /**
+ * Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
+ * back gesture animation.
+ *
+ * @param task the currently focused {@link Task}.
+ * @return a {@link BackNavigationInfo} instance containing the required leashes and metadata
+ * for the animation.
+ */
+ @Nullable
+ BackNavigationInfo startBackNavigation(@NonNull Task task) {
+ return startBackNavigation(task, null);
+ }
+
+ /**
+ * @param tx, a transaction to be used for the attaching the animation leash.
+ * This is used in tests. If null, the object will be initialized with a new {@link
+ * android.view.SurfaceControl.Transaction}
+ * @see #startBackNavigation(Task)
+ */
+ @VisibleForTesting
+ @Nullable
+ BackNavigationInfo startBackNavigation(@NonNull Task task,
+ @Nullable SurfaceControl.Transaction tx) {
+
+ if (tx == null) {
+ tx = new SurfaceControl.Transaction();
+ }
+
+ int backType = BackNavigationInfo.TYPE_UNDEFINED;
+ Task prevTask = task;
+ ActivityRecord prev;
+ WindowContainer<?> removedWindowContainer;
+ ActivityRecord activityRecord;
+ SurfaceControl animationLeashParent;
+ WindowConfiguration taskWindowConfiguration;
+ SurfaceControl animLeash;
+ HardwareBuffer screenshotBuffer = null;
+ int prevTaskId;
+ int prevUserId;
+
+ synchronized (task.mWmService.mGlobalLock) {
+ activityRecord = task.topRunningActivity();
+ removedWindowContainer = activityRecord;
+ taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
+
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, topRunningActivity=%s",
+ task, activityRecord);
+
+ // IME is visible, back gesture will dismiss it, nothing to preview.
+ if (task.getDisplayContent().getImeContainer().isVisible()) {
+ return null;
+ }
+
+ // Current Activity is home, there is no previous activity to display
+ if (activityRecord.isActivityTypeHome()) {
+ return null;
+ }
+
+ prev = task.getActivity(
+ (r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
+
+ if (prev != null) {
+ backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
+ } else if (task.returnsToHomeRootTask()) {
+ prevTask = null;
+ removedWindowContainer = task;
+ backType = BackNavigationInfo.TYPE_RETURN_TO_HOME;
+ } else if (activityRecord.isRootOfTask()) {
+ // TODO(208789724): Create single source of truth for this, maybe in
+ // RootWindowContainer
+ // TODO: Also check Task.shouldUpRecreateTaskLocked() for prev logic
+ prevTask = task.mRootWindowContainer.getTaskBelow(task);
+ removedWindowContainer = task;
+ if (prevTask.isActivityTypeHome()) {
+ backType = BackNavigationInfo.TYPE_RETURN_TO_HOME;
+ } else {
+ prev = prevTask.getTopNonFinishingActivity();
+ backType = BackNavigationInfo.TYPE_CROSS_TASK;
+ }
+ }
+
+ prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
+ prevUserId = prevTask != null ? prevTask.mUserId : 0;
+
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s",
+ prev != null ? prev.mActivityComponent : null);
+
+ //TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
+ // implemented. For now we simply have the mBackScreenshots hash map that dumbly
+ // saves the screenshots.
+ if (needsScreenshot(backType) && prev != null && prev.mActivityComponent != null) {
+ screenshotBuffer = getActivitySnapshot(task, prev.mActivityComponent);
+ }
+
+ // Prepare a leash to animate the current top window
+ animLeash = removedWindowContainer.makeAnimationLeash()
+ .setName("BackPreview Leash")
+ .setHidden(false)
+ .setBLASTLayer()
+ .build();
+ removedWindowContainer.reparentSurfaceControl(tx, animLeash);
+
+ animationLeashParent = removedWindowContainer.getAnimationLeashParent();
+ }
+
+ SurfaceControl.Builder builder = new SurfaceControl.Builder()
+ .setName("BackPreview Screenshot")
+ .setParent(animationLeashParent)
+ .setHidden(false)
+ .setBLASTLayer();
+ SurfaceControl screenshotSurface = builder.build();
+
+ // Find a screenshot of the previous activity
+
+ if (needsScreenshot(backType) && prevTask != null) {
+ if (screenshotBuffer == null) {
+ screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId);
+ }
+ }
+ tx.apply();
+
+ WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
+ try {
+ activityRecord.token.linkToDeath(
+ () -> resetSurfaces(finalRemovedWindowContainer), 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ resetSurfaces(removedWindowContainer);
+ return null;
+ }
+
+ return new BackNavigationInfo(backType,
+ animLeash,
+ screenshotSurface,
+ screenshotBuffer,
+ taskWindowConfiguration,
+ new RemoteCallback(result -> resetSurfaces(finalRemovedWindowContainer
+ )));
+ }
+
+
+ private HardwareBuffer getActivitySnapshot(@NonNull Task task,
+ ComponentName activityComponent) {
+ // Check if we have a screenshot of the previous activity, indexed by its
+ // component name.
+ SurfaceControl.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots
+ .get(activityComponent.flattenToString());
+ return backBuffer != null ? backBuffer.getHardwareBuffer() : null;
+
+ }
+
+ private HardwareBuffer getTaskSnapshot(int taskId, int userId) {
+ if (mTaskSnapshotController == null) {
+ return null;
+ }
+ TaskSnapshot snapshot = mTaskSnapshotController.getSnapshot(taskId,
+ userId, true /* restoreFromDisk */, false /* isLowResolution */);
+ return snapshot != null ? snapshot.getHardwareBuffer() : null;
+ }
+
+ private boolean needsScreenshot(int backType) {
+ switch (backType) {
+ case BackNavigationInfo.TYPE_RETURN_TO_HOME:
+ case BackNavigationInfo.TYPE_DIALOG_CLOSE:
+ return false;
+ }
+ return true;
+ }
+
+ private void resetSurfaces(@NonNull WindowContainer<?> windowContainer) {
+ synchronized (windowContainer.mWmService.mGlobalLock) {
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Back: Reset surfaces");
+ SurfaceControl.Transaction tx = windowContainer.getSyncTransaction();
+ SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
+ if (surfaceControl != null) {
+ tx.reparent(surfaceControl,
+ windowContainer.getParent().getSurfaceControl());
+ tx.apply();
+ }
+ }
+ }
+
+ void setTaskSnapshotController(@Nullable TaskSnapshotController taskSnapshotController) {
+ mTaskSnapshotController = taskSnapshotController;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index b681a96..c8781ae 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -39,6 +39,7 @@
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
@@ -100,6 +101,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@@ -254,6 +256,10 @@
private final Rect mTmpStableBounds = new Rect();
private final Rect mTmpNonDecorBounds = new Rect();
+ //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
+ // implemented
+ HashMap<String, SurfaceControl.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
+
private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
new EnsureActivitiesVisibleHelper(this);
private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
@@ -1683,6 +1689,7 @@
@Override
void addChild(WindowContainer child, int index) {
+ ActivityRecord r = topRunningActivity();
mClearedTaskForReuse = false;
boolean isAddingActivity = child.asActivityRecord() != null;
@@ -1697,6 +1704,18 @@
super.addChild(child, index);
if (isAddingActivity && task != null) {
+
+ // TODO(b/207481538): temporary per-activity screenshoting
+ if (r != null && BackNavigationController.isEnabled()) {
+ ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
+ r.mActivityComponent.flattenToString());
+ Rect outBounds = r.getBounds();
+ SurfaceControl.ScreenshotHardwareBuffer backBuffer = SurfaceControl.captureLayers(
+ r.mSurfaceControl,
+ new Rect(0, 0, outBounds.width(), outBounds.height()),
+ 1f);
+ mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
+ }
child.asActivityRecord().inHistory = true;
task.onDescendantActivityAdded(taskHadActivity, activityType, child.asActivityRecord());
}
@@ -2290,6 +2309,14 @@
void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
super.removeChild(child);
+ if (BackNavigationController.isEnabled()) {
+ //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
+ // implemented
+ ActivityRecord r = child.asActivityRecord();
+ if (r != null) {
+ mBackScreenshots.remove(r.mActivityComponent.flattenToString());
+ }
+ }
if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
removeImmediately("removeLastChild " + child);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 233f2ff..a7b7d1a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -194,7 +194,7 @@
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.tv.TvRemoteService;
-import com.android.server.tv.interactive.TvIAppManagerService;
+import com.android.server.tv.interactive.TvInteractiveAppManagerService;
import com.android.server.tv.tunerresourcemanager.TunerResourceManagerService;
import com.android.server.twilight.TwilightService;
import com.android.server.uri.UriGrantsManagerService;
@@ -2379,8 +2379,8 @@
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)
|| mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
- t.traceBegin("StartTvIAppManager");
- mSystemServiceManager.startService(TvIAppManagerService.class);
+ t.traceBegin("StartTvInteractiveAppManager");
+ mSystemServiceManager.startService(TvInteractiveAppManagerService.class);
t.traceEnd();
}
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 715fe6e..6e72479 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -18,9 +18,11 @@
import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -33,6 +35,7 @@
import android.media.midi.IMidiDeviceOpenCallback;
import android.media.midi.IMidiDeviceServer;
import android.media.midi.IMidiManager;
+import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceService;
import android.media.midi.MidiDeviceStatus;
@@ -55,6 +58,7 @@
import org.xmlpull.v1.XmlPullParser;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -96,9 +100,12 @@
= new HashMap<MidiDeviceInfo, Device>();
// list of all Bluetooth devices, keyed by BluetoothDevice
- private final HashMap<BluetoothDevice, Device> mBluetoothDevices
+ private final HashMap<BluetoothDevice, Device> mBluetoothDevices
= new HashMap<BluetoothDevice, Device>();
+ private final HashMap<BluetoothDevice, MidiDevice> mBleMidiDeviceMap =
+ new HashMap<BluetoothDevice, MidiDevice>();
+
// list of all devices, keyed by IMidiDeviceServer
private final HashMap<IBinder, Device> mDevicesByServer = new HashMap<IBinder, Device>();
@@ -569,10 +576,45 @@
}
}
+ private final BroadcastReceiver mBleMidiReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ Log.w(TAG, "MidiService, action is null");
+ return;
+ }
+
+ switch (action) {
+ case BluetoothDevice.ACTION_ACL_CONNECTED: {
+ Log.d(TAG, "ACTION_ACL_CONNECTED");
+ BluetoothDevice btDevice =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ openBluetoothDevice(btDevice);
+ }
+ break;
+
+ case BluetoothDevice.ACTION_ACL_DISCONNECTED: {
+ Log.d(TAG, "ACTION_ACL_DISCONNECTED");
+ BluetoothDevice btDevice =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ closeBluetoothDevice(btDevice);
+ }
+ break;
+ }
+ }
+ };
+
public MidiService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
+ // Setup broadcast receivers
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+ filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ context.registerReceiver(mBleMidiReceiver, filter);
+
mBluetoothServiceUid = -1;
}
@@ -701,9 +743,43 @@
}
}
+ private void openBluetoothDevice(BluetoothDevice bluetoothDevice) {
+ Log.d(TAG, "openBluetoothDevice() device: " + bluetoothDevice);
+
+ MidiManager midiManager = mContext.getSystemService(MidiManager.class);
+ midiManager.openBluetoothDevice(bluetoothDevice,
+ new MidiManager.OnDeviceOpenedListener() {
+ @Override
+ public void onDeviceOpened(MidiDevice device) {
+ synchronized (mBleMidiDeviceMap) {
+ mBleMidiDeviceMap.put(bluetoothDevice, device);
+ }
+ }
+ }, null);
+ }
+
+ private void closeBluetoothDevice(BluetoothDevice bluetoothDevice) {
+ Log.d(TAG, "closeBluetoothDevice() device: " + bluetoothDevice);
+
+ MidiDevice midiDevice;
+ synchronized (mBleMidiDeviceMap) {
+ midiDevice = mBleMidiDeviceMap.remove(bluetoothDevice);
+ }
+
+ if (midiDevice != null) {
+ try {
+ midiDevice.close();
+ } catch (IOException ex) {
+ Log.e(TAG, "Exception closing BLE-MIDI device" + ex);
+ }
+ }
+ }
+
@Override
public void openBluetoothDevice(IBinder token, BluetoothDevice bluetoothDevice,
IMidiDeviceOpenCallback callback) {
+ Log.d(TAG, "openBluetoothDevice()");
+
Client client = getClient(token);
if (client == null) return;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
index a06a782..fc55a9f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
@@ -52,7 +52,7 @@
@Mock
private ClientMonitorCallbackConverter mClientCallback;
@Mock
- private BaseClientMonitor.Callback mSchedulerCallback;
+ private ClientMonitorCallback mSchedulerCallback;
@Before
public void setUp() {
@@ -96,7 +96,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
startHalOperation();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java
new file mode 100644
index 0000000..51d234d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 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.biometrics.sensors;
+
+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.verify;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.log.BiometricLogger;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class BaseClientMonitorTest {
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private IBinder mToken;
+ private @Mock ClientMonitorCallbackConverter mListener;
+ @Mock
+ private BiometricLogger mLogger;
+ @Mock
+ private ClientMonitorCallback mCallback;
+
+ private TestClientMonitor mClientMonitor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mClientMonitor = new TestClientMonitor();
+ }
+
+ @Test
+ public void preparesForDeath() throws RemoteException {
+ verify(mToken).linkToDeath(eq(mClientMonitor), anyInt());
+
+ mClientMonitor.binderDied();
+
+ assertThat(mClientMonitor.mCanceled).isTrue();
+ assertThat(mClientMonitor.getListener()).isNull();
+ }
+
+ @Test
+ public void ignoresDeathWhenDone() {
+ mClientMonitor.markAlreadyDone();
+ mClientMonitor.binderDied();
+
+ assertThat(mClientMonitor.mCanceled).isFalse();
+ }
+
+ @Test
+ public void start() {
+ mClientMonitor.start(mCallback);
+
+ verify(mCallback).onClientStarted(eq(mClientMonitor));
+ }
+
+ @Test
+ public void destroy() {
+ mClientMonitor.destroy();
+ mClientMonitor.destroy();
+
+ assertThat(mClientMonitor.isAlreadyDone()).isTrue();
+ verify(mToken).unlinkToDeath(eq(mClientMonitor), anyInt());
+ }
+
+ @Test
+ public void hasRequestId() {
+ assertThat(mClientMonitor.hasRequestId()).isFalse();
+
+ final int id = 200;
+ mClientMonitor.setRequestId(id);
+ assertThat(mClientMonitor.hasRequestId()).isTrue();
+ assertThat(mClientMonitor.getRequestId()).isEqualTo(id);
+ }
+
+ private class TestClientMonitor extends BaseClientMonitor implements Interruptable {
+ public boolean mCanceled = false;
+
+ TestClientMonitor() {
+ super(mContext, mToken, mListener, 9 /* userId */, "foo" /* owner */, 2 /* cookie */,
+ 5 /* sensorId */, mLogger);
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return 0;
+ }
+
+ @Override
+ public void cancel() {
+ mCanceled = true;
+ }
+
+ @Override
+ public void cancelWithoutStarting(@NonNull ClientMonitorCallback callback) {
+ mCanceled = true;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index d4bac2c..8751cf3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -61,11 +61,11 @@
@Mock
private InterruptableMonitor<FakeHal> mClientMonitor;
@Mock
- private BaseClientMonitor.Callback mClientCallback;
+ private ClientMonitorCallback mClientCallback;
@Mock
private FakeHal mHal;
@Captor
- ArgumentCaptor<BaseClientMonitor.Callback> mStartCallback;
+ ArgumentCaptor<ClientMonitorCallback> mStartCallback;
private Handler mHandler;
private BiometricSchedulerOperation mOperation;
@@ -89,7 +89,7 @@
assertThat(mOperation.isFinished()).isFalse();
final boolean started = mOperation.startWithCookie(
- mock(BaseClientMonitor.Callback.class), cookie);
+ mock(ClientMonitorCallback.class), cookie);
assertThat(started).isTrue();
verify(mClientMonitor).start(mStartCallback.capture());
@@ -106,7 +106,7 @@
assertThat(mOperation.isReadyToStart()).isEqualTo(goodCookie);
final boolean started = mOperation.startWithCookie(
- mock(BaseClientMonitor.Callback.class), badCookie);
+ mock(ClientMonitorCallback.class), badCookie);
assertThat(started).isFalse();
assertThat(mOperation.isStarted()).isFalse();
@@ -119,7 +119,7 @@
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final BaseClientMonitor.Callback cb = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
mOperation.start(cb);
verify(mClientMonitor).start(mStartCallback.capture());
mStartCallback.getValue().onClientStarted(mClientMonitor);
@@ -146,7 +146,7 @@
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(null);
- final BaseClientMonitor.Callback cb = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
mOperation.start(cb);
verify(mClientMonitor, never()).start(any());
@@ -164,17 +164,17 @@
public void doesNotStartWithCookie() {
when(mClientMonitor.getCookie()).thenReturn(9);
assertThrows(IllegalStateException.class,
- () -> mOperation.start(mock(BaseClientMonitor.Callback.class)));
+ () -> mOperation.start(mock(ClientMonitorCallback.class)));
}
@Test
public void cannotRestart() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(BaseClientMonitor.Callback.class));
+ mOperation.start(mock(ClientMonitorCallback.class));
assertThrows(IllegalStateException.class,
- () -> mOperation.start(mock(BaseClientMonitor.Callback.class)));
+ () -> mOperation.start(mock(ClientMonitorCallback.class)));
}
@Test
@@ -187,14 +187,14 @@
verify(mClientMonitor).unableToStart();
verify(mClientMonitor).destroy();
assertThrows(IllegalStateException.class,
- () -> mOperation.start(mock(BaseClientMonitor.Callback.class)));
+ () -> mOperation.start(mock(ClientMonitorCallback.class)));
}
@Test
public void cannotAbortRunning() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(BaseClientMonitor.Callback.class));
+ mOperation.start(mock(ClientMonitorCallback.class));
assertThrows(IllegalStateException.class, () -> mOperation.abort());
}
@@ -203,8 +203,8 @@
public void cancel() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final BaseClientMonitor.Callback startCb = mock(BaseClientMonitor.Callback.class);
- final BaseClientMonitor.Callback cancelCb = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback startCb = mock(ClientMonitorCallback.class);
+ final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
mOperation.start(startCb);
verify(mClientMonitor).start(mStartCallback.capture());
mStartCallback.getValue().onClientStarted(mClientMonitor);
@@ -230,12 +230,12 @@
public void cancelWithoutStarting() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final BaseClientMonitor.Callback cancelCb = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
mOperation.cancel(mHandler, cancelCb);
assertThat(mOperation.isCanceling()).isTrue();
- ArgumentCaptor<BaseClientMonitor.Callback> cbCaptor =
- ArgumentCaptor.forClass(BaseClientMonitor.Callback.class);
+ ArgumentCaptor<ClientMonitorCallback> cbCaptor =
+ ArgumentCaptor.forClass(ClientMonitorCallback.class);
verify(mClientMonitor).cancelWithoutStarting(cbCaptor.capture());
cbCaptor.getValue().onClientFinished(mClientMonitor, true);
@@ -278,7 +278,7 @@
}
mOperation.markCanceling();
- final BaseClientMonitor.Callback cb = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
if (withCookie != null) {
mOperation.startWithCookie(cb, withCookie);
} else {
@@ -307,12 +307,12 @@
private void cancelWatchdog(boolean start) {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(BaseClientMonitor.Callback.class));
+ mOperation.start(mock(ClientMonitorCallback.class));
if (start) {
verify(mClientMonitor).start(mStartCallback.capture());
mStartCallback.getValue().onClientStarted(mClientMonitor);
}
- mOperation.cancel(mHandler, mock(BaseClientMonitor.Callback.class));
+ mOperation.cancel(mHandler, mock(ClientMonitorCallback.class));
assertThat(mOperation.isCanceling()).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index ac08319..c99d656 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -114,13 +114,13 @@
final TestHalClientMonitor client2 = new TestHalClientMonitor(
mContext, mToken, () -> mock(Object.class));
- final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
- final BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
+ final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class);
// Pretend the scheduler is busy so the first operation doesn't start right away. We want
// to pretend like there are two operations in the queue before kicking things off
mScheduler.mCurrentOperation = new BiometricSchedulerOperation(
- mock(BaseClientMonitor.class), mock(BaseClientMonitor.Callback.class));
+ mock(BaseClientMonitor.class), mock(ClientMonitorCallback.class));
mScheduler.scheduleClientMonitor(client1, callback1);
assertEquals(1, mScheduler.mPendingOperations.size());
@@ -152,13 +152,13 @@
final TestHalClientMonitor client2 =
new TestHalClientMonitor(mContext, mToken, () -> daemon2);
- final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
- final BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
+ final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class);
// Pretend the scheduler is busy so the first operation doesn't start right away. We want
// to pretend like there are two operations in the queue before kicking things off
mScheduler.mCurrentOperation = new BiometricSchedulerOperation(
- mock(BaseClientMonitor.class), mock(BaseClientMonitor.Callback.class));
+ mock(BaseClientMonitor.class), mock(ClientMonitorCallback.class));
mScheduler.scheduleClientMonitor(client1, callback1);
assertEquals(1, mScheduler.mPendingOperations.size());
@@ -187,7 +187,7 @@
final HalClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> mock(Object.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class));
- final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
+ final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
// Schedule a BiometricPrompt authentication request
mScheduler.scheduleClientMonitor(client1, callback1);
@@ -628,7 +628,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
assertFalse(mStarted);
mStarted = true;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java
index 09b5c5c..587bb60 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java
@@ -17,36 +17,62 @@
package com.android.server.biometrics.sensors;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Objects;
@Presubmit
@SmallTest
public class CompositeCallbackTest {
+ @Mock
+ private BaseClientMonitor mClientMonitor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
@Test
- public void testNullCallback() {
- BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
- BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class);
- BaseClientMonitor.Callback callback3 = null;
+ public void testCallbacks() {
+ testCallbacks(mock(ClientMonitorCallback.class), mock(ClientMonitorCallback.class));
+ }
- BaseClientMonitor.CompositeCallback callback = new BaseClientMonitor.CompositeCallback(
- callback1, callback2, callback3);
+ @Test
+ public void testNullCallbacks() {
+ testCallbacks(null, mock(ClientMonitorCallback.class),
+ null, mock(ClientMonitorCallback.class));
+ }
- BaseClientMonitor clientMonitor = mock(BaseClientMonitor.class);
+ private void testCallbacks(ClientMonitorCallback... callbacks) {
+ final ClientMonitorCallback[] expected = Arrays.stream(callbacks)
+ .filter(Objects::nonNull).toArray(ClientMonitorCallback[]::new);
- callback.onClientStarted(clientMonitor);
- verify(callback1).onClientStarted(eq(clientMonitor));
- verify(callback2).onClientStarted(eq(clientMonitor));
+ ClientMonitorCompositeCallback callback = new ClientMonitorCompositeCallback(callbacks);
- callback.onClientFinished(clientMonitor, true /* success */);
- verify(callback1).onClientFinished(eq(clientMonitor), eq(true));
- verify(callback2).onClientFinished(eq(clientMonitor), eq(true));
+ callback.onClientStarted(mClientMonitor);
+ final InOrder order = inOrder(expected);
+ for (ClientMonitorCallback cb : expected) {
+ order.verify(cb).onClientStarted(eq(mClientMonitor));
+ }
+
+ callback.onClientFinished(mClientMonitor, true /* success */);
+ Collections.reverse(Arrays.asList(expected));
+ for (ClientMonitorCallback cb : expected) {
+ order.verify(cb).onClientFinished(eq(mClientMonitor), eq(true));
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 407f5fb..a11709a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -155,7 +155,7 @@
assertNull(mScheduler.mCurrentOperation);
final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
- mock(BaseClientMonitor.class), new BaseClientMonitor.Callback() {});
+ mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
mScheduler.mCurrentOperation = fakeOperation;
startUserClient.mCallback.onClientFinished(startUserClient, true);
assertSame(fakeOperation, mScheduler.mCurrentOperation);
@@ -234,7 +234,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
onUserStopped();
}
@@ -248,7 +248,7 @@
private static class TestStartUserClient extends StartUserClient<Object, Object> {
private final boolean mShouldFinish;
- Callback mCallback;
+ ClientMonitorCallback mCallback;
public TestStartUserClient(@NonNull Context context,
@NonNull LazyDaemon<Object> lazyDaemon, @Nullable IBinder token, int userId,
@@ -263,7 +263,7 @@
}
@Override
- public void start(@NonNull Callback callback) {
+ public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mCallback = callback;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java
index 55dc035..931fad1 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java
@@ -34,7 +34,7 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import org.junit.Before;
@@ -61,7 +61,7 @@
@Mock
private IFaceServiceReceiver mOtherReceiver;
@Mock
- private BaseClientMonitor.Callback mMonitorCallback;
+ private ClientMonitorCallback mMonitorCallback;
private FaceGenerateChallengeClient mClient;
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index d164d2a..0e98b5e 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,6 +39,7 @@
import android.app.StatusBarManager;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.om.IOverlayManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -96,6 +98,10 @@
private ApplicationInfo mApplicationInfo;
@Mock
private IStatusBar.Stub mMockStatusBar;
+ @Mock
+ private IOverlayManager mOverlayManager;
+ @Mock
+ private PackageManager mPackageManager;
@Captor
private ArgumentCaptor<IAddTileResultCallback> mAddTileResultCallbackCaptor;
@@ -130,6 +136,7 @@
mStatusBarManagerService);
mStatusBarManagerService.registerStatusBar(mMockStatusBar);
+ mStatusBarManagerService.registerOverlayManager(mOverlayManager);
mIcon = Icon.createWithResource(mContext, android.R.drawable.btn_plus);
}
@@ -577,27 +584,56 @@
}
@Test
- public void testSetNavBarModeOverride_setsOverrideModeKids() {
+ public void testSetNavBarModeOverride_setsOverrideModeKids() throws RemoteException {
int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+
mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ verify(mOverlayManager).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_setsOverrideModeNone() {
+ public void testSetNavBarModeOverride_setsOverrideModeNone() throws RemoteException {
int navBarModeOverrideNone = StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+
mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideNone);
assertEquals(navBarModeOverrideNone, mStatusBarManagerService.getNavBarModeOverride());
+ verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_invalidInputThrowsError() {
+ public void testSetNavBarModeOverride_invalidInputThrowsError() throws RemoteException {
int navBarModeOverrideInvalid = -1;
assertThrows(UnsupportedOperationException.class,
() -> mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideInvalid));
+ verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
+ }
+
+ @Test
+ public void testSetNavBarModeOverride_noOverlayManagerDoesNotEnable() throws RemoteException {
+ mOverlayManager = null;
+ int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+
+ mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+
+ assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
+ }
+
+ @Test
+ public void testSetNavBarModeOverride_noPackageDoesNotEnable() throws Exception {
+ mContext.setMockPackageManager(mPackageManager);
+ when(mPackageManager.getPackageInfo(anyString(),
+ any(PackageManager.PackageInfoFlags.class))).thenReturn(null);
+ int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+
+ mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+
+ assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
private void mockUidCheck() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
new file mode 100644
index 0000000..687779d
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static android.window.BackNavigationInfo.typeToString;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.hardware.HardwareBuffer;
+import android.platform.test.annotations.Presubmit;
+import android.window.BackNavigationInfo;
+import android.window.TaskSnapshot;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class BackNavigationControllerTests extends WindowTestsBase {
+
+ private BackNavigationController mBackNavigationController;
+
+ @Before
+ public void setUp() throws Exception {
+ mBackNavigationController = new BackNavigationController();
+ }
+
+ @Test
+ public void backTypeHomeWhenBackToLauncher() {
+ Task task = createTopTaskWithActivity();
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(backNavigationInfo).isNotNull();
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+ }
+
+ @Test
+ public void backTypeCrossTaskWhenBackToPreviousTask() {
+ Task taskA = createTask(mDefaultDisplay);
+ createActivityRecord(taskA);
+ Task task = createTopTaskWithActivity();
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(backNavigationInfo).isNotNull();
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_TASK));
+ }
+
+ @Test
+ public void backTypeCrossActivityWhenBackToPreviousActivity() {
+ Task task = createTopTaskWithActivity();
+ mAtm.setFocusedTask(task.mTaskId, createActivityRecord(task));
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(backNavigationInfo).isNotNull();
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY));
+ }
+
+ /**
+ * Checks that we are able to fill all the field of the {@link BackNavigationInfo} object.
+ */
+ @Test
+ public void backNavInfoFullyPopulated() {
+ Task task = createTopTaskWithActivity();
+ createActivityRecord(task);
+
+ // We need a mock screenshot so
+ TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
+
+ mBackNavigationController.setTaskSnapshotController(taskSnapshotController);
+
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(backNavigationInfo).isNotNull();
+ assertThat(backNavigationInfo.getDepartingWindowContainer()).isNotNull();
+ assertThat(backNavigationInfo.getScreenshotSurface()).isNotNull();
+ assertThat(backNavigationInfo.getScreenshotHardwareBuffer()).isNotNull();
+ assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
+ }
+
+ @NonNull
+ private TaskSnapshotController createMockTaskSnapshotController() {
+ TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
+ TaskSnapshot taskSnapshot = mock(TaskSnapshot.class);
+ when(taskSnapshot.getHardwareBuffer()).thenReturn(mock(HardwareBuffer.class));
+ when(taskSnapshotController.getSnapshot(anyInt(), anyInt(), anyBoolean(), anyBoolean()))
+ .thenReturn(taskSnapshot);
+ return taskSnapshotController;
+ }
+
+ @NonNull
+ private Task createTopTaskWithActivity() {
+ Task task = createTask(mDefaultDisplay);
+ ActivityRecord record = createActivityRecord(task);
+ when(record.mSurfaceControl.isValid()).thenReturn(true);
+ mAtm.setFocusedTask(task.mTaskId, record);
+ return task;
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 88725a6..0d88a0d 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -61,6 +61,7 @@
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -70,6 +71,7 @@
import android.util.Slog;
import android.util.SparseLongArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
@@ -128,6 +130,12 @@
private final CopyOnWriteArrayList<Pair<String, StorageStatsAugmenter>>
mStorageStatsAugmenters = new CopyOnWriteArrayList<>();
+ @GuardedBy("mLock")
+ private int
+ mStorageThresholdPercentHigh = StorageManager.DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH;
+
+ private final Object mLock = new Object();
+
public StorageStatsService(Context context) {
mContext = Preconditions.checkNotNull(context);
mAppOps = Preconditions.checkNotNull(context.getSystemService(AppOpsManager.class));
@@ -173,6 +181,19 @@
}
}
}, prFilter);
+
+ updateConfig();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ mContext.getMainExecutor(), properties -> updateConfig());
+ }
+
+ private void updateConfig() {
+ synchronized (mLock) {
+ mStorageThresholdPercentHigh = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH_KEY,
+ StorageManager.DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH);
+ }
}
private void invalidateMounts() {
@@ -554,7 +575,7 @@
* By only triggering a re-calculation after the storage has changed sizes, we can avoid
* recalculating quotas too often. Minimum change delta high and low define the
* percentage of change we need to see before we recalculate quotas when the device has
- * enough storage space (more than StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total
+ * enough storage space (more than mStorageThresholdPercentHigh of total
* free) and in low storage condition respectively.
*/
private static final long MINIMUM_CHANGE_DELTA_PERCENT_HIGH = 5;
@@ -588,11 +609,15 @@
mStats.restat(Environment.getDataDirectory().getAbsolutePath());
long bytesDelta = Math.abs(mPreviousBytes - mStats.getAvailableBytes());
long bytesDeltaThreshold;
- if (mStats.getAvailableBytes() > mTotalBytes
- * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
- bytesDeltaThreshold = mTotalBytes * MINIMUM_CHANGE_DELTA_PERCENT_HIGH / 100;
- } else {
- bytesDeltaThreshold = mTotalBytes * MINIMUM_CHANGE_DELTA_PERCENT_LOW / 100;
+ synchronized (mLock) {
+ if (mStats.getAvailableBytes() > mTotalBytes
+ * mStorageThresholdPercentHigh / 100) {
+ bytesDeltaThreshold = mTotalBytes
+ * MINIMUM_CHANGE_DELTA_PERCENT_HIGH / 100;
+ } else {
+ bytesDeltaThreshold = mTotalBytes
+ * MINIMUM_CHANGE_DELTA_PERCENT_LOW / 100;
+ }
}
if (bytesDelta > bytesDeltaThreshold) {
mPreviousBytes = mStats.getAvailableBytes();
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS
new file mode 100644
index 0000000..f7c0a87
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS
@@ -0,0 +1,2 @@
+# window manager > animations/transitions
+# Bug component: 316275
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS
new file mode 100644
index 0000000..301fafa
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS
@@ -0,0 +1,2 @@
+# ime
+# Bug component: 34867
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS
new file mode 100644
index 0000000..2c414a2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS
@@ -0,0 +1,4 @@
+# System UI > ... > Overview (recent apps) > UI
+# Bug template url: https://b.corp.google.com/issues/new?component=807991&template=1390280 = per-file *Overview*
+# window manager > animations/transitions
+# Bug template url: https://b.corp.google.com/issues/new?component=316275&template=1018192
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS
new file mode 100644
index 0000000..897fe5d
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS
@@ -0,0 +1,2 @@
+# System UI > ... > Launcher > Gesture nav
+# Bug component: 565144
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS
new file mode 100644
index 0000000..f7c0a87
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS
@@ -0,0 +1,2 @@
+# window manager > animations/transitions
+# Bug component: 316275