diff options
257 files changed, 6592 insertions, 2811 deletions
diff --git a/Android.bp b/Android.bp index d5d5150886d4..7d02d7d50f84 100644 --- a/Android.bp +++ b/Android.bp @@ -423,7 +423,6 @@ filegroup { // TODO: remove these annotations as soon as we can use andoid.support.annotations.* ":framework-annotations", ":modules-utils-preconditions-srcs", - "core/java/android/net/DhcpResults.java", "core/java/android/util/IndentingPrintWriter.java", "core/java/android/util/LocalLog.java", "core/java/com/android/internal/util/HexDump.java", @@ -583,6 +582,7 @@ stubs_defaults { libs: [ "art.module.public.api", "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-tiramisu", "sdk_public_current_framework-bluetooth", // There are a few classes from modules used by the core that // need to be resolved by metalava. We use a prebuilt stub of the diff --git a/StubLibraries.bp b/StubLibraries.bp index a0a426e9b766..92e7dc98e244 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -258,6 +258,7 @@ java_library { srcs: [":module-lib-api-stubs-docs-non-updatable"], libs: [ "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-tiramisu", "sdk_public_current_framework-bluetooth", // NOTE: The below can be removed once the prebuilt stub contains bluetooth. "sdk_system_current_android", diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt index 50e0a1b45c9d..e346ebf827ae 100644 --- a/boot/hiddenapi/hiddenapi-max-target-o.txt +++ b/boot/hiddenapi/hiddenapi-max-target-o.txt @@ -9315,78 +9315,6 @@ Landroid/app/usage/IUsageStatsManager;->setAppStandbyBucket(Ljava/lang/String;II Landroid/app/usage/IUsageStatsManager;->setAppStandbyBuckets(Landroid/content/pm/ParceledListSlice;I)V Landroid/app/usage/IUsageStatsManager;->unregisterAppUsageObserver(ILjava/lang/String;)V Landroid/app/usage/IUsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JI)V -Landroid/app/usage/NetworkStats$Bucket;->convertDefaultNetworkStatus(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertMetered(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertRoaming(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertSet(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertState(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertTag(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertUid(I)I -Landroid/app/usage/NetworkStats$Bucket;->mBeginTimeStamp:J -Landroid/app/usage/NetworkStats$Bucket;->mDefaultNetworkStatus:I -Landroid/app/usage/NetworkStats$Bucket;->mEndTimeStamp:J -Landroid/app/usage/NetworkStats$Bucket;->mMetered:I -Landroid/app/usage/NetworkStats$Bucket;->mRoaming:I -Landroid/app/usage/NetworkStats$Bucket;->mRxBytes:J -Landroid/app/usage/NetworkStats$Bucket;->mRxPackets:J -Landroid/app/usage/NetworkStats$Bucket;->mState:I -Landroid/app/usage/NetworkStats$Bucket;->mTag:I -Landroid/app/usage/NetworkStats$Bucket;->mTxBytes:J -Landroid/app/usage/NetworkStats$Bucket;->mTxPackets:J -Landroid/app/usage/NetworkStats$Bucket;->mUid:I -Landroid/app/usage/NetworkStats;-><init>(Landroid/content/Context;Landroid/net/NetworkTemplate;IJJLandroid/net/INetworkStatsService;)V -Landroid/app/usage/NetworkStats;->fillBucketFromSummaryEntry(Landroid/app/usage/NetworkStats$Bucket;)V -Landroid/app/usage/NetworkStats;->getDeviceSummaryForNetwork()Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStats;->getNextHistoryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z -Landroid/app/usage/NetworkStats;->getNextSummaryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z -Landroid/app/usage/NetworkStats;->getSummaryAggregate()Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStats;->getUid()I -Landroid/app/usage/NetworkStats;->hasNextUid()Z -Landroid/app/usage/NetworkStats;->isUidEnumeration()Z -Landroid/app/usage/NetworkStats;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/app/usage/NetworkStats;->mEndTimeStamp:J -Landroid/app/usage/NetworkStats;->mEnumerationIndex:I -Landroid/app/usage/NetworkStats;->mHistory:Landroid/net/NetworkStatsHistory; -Landroid/app/usage/NetworkStats;->mRecycledHistoryEntry:Landroid/net/NetworkStatsHistory$Entry; -Landroid/app/usage/NetworkStats;->mRecycledSummaryEntry:Landroid/net/NetworkStats$Entry; -Landroid/app/usage/NetworkStats;->mSession:Landroid/net/INetworkStatsSession; -Landroid/app/usage/NetworkStats;->mStartTimeStamp:J -Landroid/app/usage/NetworkStats;->mState:I -Landroid/app/usage/NetworkStats;->mSummary:Landroid/net/NetworkStats; -Landroid/app/usage/NetworkStats;->mTag:I -Landroid/app/usage/NetworkStats;->mTemplate:Landroid/net/NetworkTemplate; -Landroid/app/usage/NetworkStats;->mUidOrUidIndex:I -Landroid/app/usage/NetworkStats;->mUids:[I -Landroid/app/usage/NetworkStats;->setSingleUidTagState(III)V -Landroid/app/usage/NetworkStats;->startHistoryEnumeration(III)V -Landroid/app/usage/NetworkStats;->startSummaryEnumeration()V -Landroid/app/usage/NetworkStats;->startUserUidEnumeration()V -Landroid/app/usage/NetworkStats;->stepHistory()V -Landroid/app/usage/NetworkStats;->stepUid()V -Landroid/app/usage/NetworkStats;->TAG:Ljava/lang/String; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;-><init>(Landroid/os/Looper;ILjava/lang/String;Landroid/app/usage/NetworkStatsManager$UsageCallback;)V -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->getObject(Landroid/os/Message;Ljava/lang/String;)Ljava/lang/Object; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mCallback:Landroid/app/usage/NetworkStatsManager$UsageCallback; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mNetworkType:I -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mSubscriberId:Ljava/lang/String; -Landroid/app/usage/NetworkStatsManager$UsageCallback;->request:Landroid/net/DataUsageRequest; -Landroid/app/usage/NetworkStatsManager;-><init>(Landroid/content/Context;Landroid/net/INetworkStatsService;)V -Landroid/app/usage/NetworkStatsManager;->CALLBACK_LIMIT_REACHED:I -Landroid/app/usage/NetworkStatsManager;->CALLBACK_RELEASED:I -Landroid/app/usage/NetworkStatsManager;->createTemplate(ILjava/lang/String;)Landroid/net/NetworkTemplate; -Landroid/app/usage/NetworkStatsManager;->DBG:Z -Landroid/app/usage/NetworkStatsManager;->FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN:I -Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_FORCE:I -Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_ON_OPEN:I -Landroid/app/usage/NetworkStatsManager;->mContext:Landroid/content/Context; -Landroid/app/usage/NetworkStatsManager;->mFlags:I -Landroid/app/usage/NetworkStatsManager;->MIN_THRESHOLD_BYTES:J -Landroid/app/usage/NetworkStatsManager;->mService:Landroid/net/INetworkStatsService; -Landroid/app/usage/NetworkStatsManager;->querySummaryForDevice(Landroid/net/NetworkTemplate;JJ)Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStatsManager;->registerUsageCallback(Landroid/net/NetworkTemplate;IJLandroid/app/usage/NetworkStatsManager$UsageCallback;Landroid/os/Handler;)V -Landroid/app/usage/NetworkStatsManager;->setAugmentWithSubscriptionPlan(Z)V -Landroid/app/usage/NetworkStatsManager;->setPollOnOpen(Z)V -Landroid/app/usage/NetworkStatsManager;->TAG:Ljava/lang/String; Landroid/app/usage/StorageStats;-><init>()V Landroid/app/usage/StorageStats;-><init>(Landroid/os/Parcel;)V Landroid/app/usage/StorageStats;->cacheBytes:J @@ -35338,13 +35266,6 @@ Landroid/net/ConnectivityMetricsEvent;->transports:J Landroid/net/Credentials;->gid:I Landroid/net/Credentials;->pid:I Landroid/net/Credentials;->uid:I -Landroid/net/DataUsageRequest;-><init>(ILandroid/net/NetworkTemplate;J)V -Landroid/net/DataUsageRequest;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/DataUsageRequest;->PARCELABLE_KEY:Ljava/lang/String; -Landroid/net/DataUsageRequest;->requestId:I -Landroid/net/DataUsageRequest;->REQUEST_ID_UNSET:I -Landroid/net/DataUsageRequest;->template:Landroid/net/NetworkTemplate; -Landroid/net/DataUsageRequest;->thresholdInBytes:J Landroid/net/DhcpResults;->addDns(Ljava/lang/String;)Z Landroid/net/DhcpResults;->clear()V Landroid/net/DhcpResults;->CREATOR:Landroid/os/Parcelable$Creator; @@ -35793,68 +35714,6 @@ Landroid/net/INetworkScoreService;->requestScores([Landroid/net/NetworkKey;)Z Landroid/net/INetworkScoreService;->setActiveScorer(Ljava/lang/String;)Z Landroid/net/INetworkScoreService;->unregisterNetworkScoreCache(ILandroid/net/INetworkScoreCache;)V Landroid/net/INetworkScoreService;->updateScores([Landroid/net/ScoredNetwork;)Z -Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdate()V -Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdateIfaces([Landroid/net/Network;)V -Landroid/net/INetworkStatsService$Stub$Proxy;->getDataLayerSnapshotForUid(I)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService$Stub$Proxy;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService$Stub$Proxy;->getIfaceStats(Ljava/lang/String;I)J -Landroid/net/INetworkStatsService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub$Proxy;->getTotalStats(I)J -Landroid/net/INetworkStatsService$Stub$Proxy;->getUidStats(II)J -Landroid/net/INetworkStatsService$Stub$Proxy;->incrementOperationCount(III)V -Landroid/net/INetworkStatsService$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/INetworkStatsService$Stub$Proxy;->openSession()Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsService$Stub$Proxy;->openSessionForUsageStats(ILjava/lang/String;)Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsService$Stub$Proxy;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest; -Landroid/net/INetworkStatsService$Stub$Proxy;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V -Landroid/net/INetworkStatsService$Stub;-><init>()V -Landroid/net/INetworkStatsService$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdate:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdateIfaces:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDataLayerSnapshotForUid:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDetailedUidStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getIfaceStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getMobileIfaces:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getTotalStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getUidStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_incrementOperationCount:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSession:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSessionForUsageStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_registerUsageCallback:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_unregisterUsageRequest:I -Landroid/net/INetworkStatsService;->forceUpdateIfaces([Landroid/net/Network;)V -Landroid/net/INetworkStatsService;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService;->getIfaceStats(Ljava/lang/String;I)J -Landroid/net/INetworkStatsService;->getTotalStats(I)J -Landroid/net/INetworkStatsService;->getUidStats(II)J -Landroid/net/INetworkStatsService;->incrementOperationCount(III)V -Landroid/net/INetworkStatsService;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest; -Landroid/net/INetworkStatsService;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V -Landroid/net/INetworkStatsSession$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/INetworkStatsSession$Stub$Proxy;->close()V -Landroid/net/INetworkStatsSession$Stub$Proxy;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getRelevantUids()[I -Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForAllUid(Landroid/net/NetworkTemplate;JJZ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/INetworkStatsSession$Stub;-><init>()V -Landroid/net/INetworkStatsSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsSession$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_close:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getDeviceSummaryForNetwork:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForNetwork:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryIntervalForUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getRelevantUids:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForAllUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForNetwork:I -Landroid/net/INetworkStatsSession;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession;->getRelevantUids()[I Landroid/net/InterfaceConfiguration;->CREATOR:Landroid/os/Parcelable$Creator; Landroid/net/InterfaceConfiguration;->FLAG_DOWN:Ljava/lang/String; Landroid/net/InterfaceConfiguration;->FLAG_UP:Ljava/lang/String; @@ -36529,41 +36388,6 @@ Landroid/net/SSLSessionCache;->TAG:Ljava/lang/String; Landroid/net/StringNetworkSpecifier;-><init>(Ljava/lang/String;)V Landroid/net/StringNetworkSpecifier;->CREATOR:Landroid/os/Parcelable$Creator; Landroid/net/StringNetworkSpecifier;->satisfiedBy(Landroid/net/NetworkSpecifier;)Z -Landroid/net/TrafficStats;->addIfSupported(J)J -Landroid/net/TrafficStats;->closeQuietly(Landroid/net/INetworkStatsSession;)V -Landroid/net/TrafficStats;->GB_IN_BYTES:J -Landroid/net/TrafficStats;->getDataLayerSnapshotForUid(Landroid/content/Context;)Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->getRxPackets(Ljava/lang/String;)J -Landroid/net/TrafficStats;->getTxPackets(Ljava/lang/String;)J -Landroid/net/TrafficStats;->KB_IN_BYTES:J -Landroid/net/TrafficStats;->LOOPBACK_IFACE:Ljava/lang/String; -Landroid/net/TrafficStats;->MB_IN_BYTES:J -Landroid/net/TrafficStats;->PB_IN_BYTES:J -Landroid/net/TrafficStats;->sActiveProfilingStart:Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->sProfilingLock:Ljava/lang/Object; -Landroid/net/TrafficStats;->sStatsService:Landroid/net/INetworkStatsService; -Landroid/net/TrafficStats;->startDataProfiling(Landroid/content/Context;)V -Landroid/net/TrafficStats;->stopDataProfiling(Landroid/content/Context;)Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->TAG_SYSTEM_APP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_BACKUP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_DHCP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_DOWNLOAD:I -Landroid/net/TrafficStats;->TAG_SYSTEM_GPS:I -Landroid/net/TrafficStats;->TAG_SYSTEM_MEDIA:I -Landroid/net/TrafficStats;->TAG_SYSTEM_NEIGHBOR:I -Landroid/net/TrafficStats;->TAG_SYSTEM_NTP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_PAC:I -Landroid/net/TrafficStats;->TAG_SYSTEM_PROBE:I -Landroid/net/TrafficStats;->TAG_SYSTEM_RESTORE:I -Landroid/net/TrafficStats;->TB_IN_BYTES:J -Landroid/net/TrafficStats;->TYPE_RX_BYTES:I -Landroid/net/TrafficStats;->TYPE_RX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TCP_RX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TCP_TX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TX_BYTES:I -Landroid/net/TrafficStats;->TYPE_TX_PACKETS:I -Landroid/net/TrafficStats;->UID_REMOVED:I -Landroid/net/TrafficStats;->UID_TETHERING:I Landroid/net/Uri$AbstractHierarchicalUri;-><init>()V Landroid/net/Uri$AbstractHierarchicalUri;->getUserInfoPart()Landroid/net/Uri$Part; Landroid/net/Uri$AbstractHierarchicalUri;->host:Ljava/lang/String; diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt index 522e88f82e25..033afb676381 100644 --- a/boot/hiddenapi/hiddenapi-unsupported.txt +++ b/boot/hiddenapi/hiddenapi-unsupported.txt @@ -168,9 +168,6 @@ Landroid/media/tv/ITvRemoteProvider$Stub;-><init>()V Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager; Landroid/net/INetworkScoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkScoreService; -Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService; Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/os/IDeviceIdentifiersPolicyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdentifiersPolicyService; Landroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController; diff --git a/core/api/current.txt b/core/api/current.txt index da14dfeec5c8..1e79e523659f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -135,6 +135,9 @@ package android { 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_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO"; + field public static final String READ_MEDIA_IMAGE = "android.permission.READ_MEDIA_IMAGE"; + field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO"; field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY"; field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS"; field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; @@ -220,6 +223,8 @@ package android { field public static final String NEARBY_DEVICES = "android.permission-group.NEARBY_DEVICES"; field public static final String NOTIFICATIONS = "android.permission-group.NOTIFICATIONS"; field public static final String PHONE = "android.permission-group.PHONE"; + field public static final String READ_MEDIA_AURAL = "android.permission-group.READ_MEDIA_AURAL"; + field public static final String READ_MEDIA_VISUAL = "android.permission-group.READ_MEDIA_VISUAL"; field public static final String SENSORS = "android.permission-group.SENSORS"; field public static final String SMS = "android.permission-group.SMS"; field public static final String STORAGE = "android.permission-group.STORAGE"; @@ -3592,17 +3597,17 @@ package android.animation { } public static interface Animator.AnimatorListener { - method public void onAnimationCancel(android.animation.Animator); - method public default void onAnimationEnd(android.animation.Animator, boolean); - method public void onAnimationEnd(android.animation.Animator); - method public void onAnimationRepeat(android.animation.Animator); - method public default void onAnimationStart(android.animation.Animator, boolean); - method public void onAnimationStart(android.animation.Animator); + method public void onAnimationCancel(@NonNull android.animation.Animator); + method public default void onAnimationEnd(@NonNull android.animation.Animator, boolean); + method public void onAnimationEnd(@NonNull android.animation.Animator); + method public void onAnimationRepeat(@NonNull android.animation.Animator); + method public default void onAnimationStart(@NonNull android.animation.Animator, boolean); + method public void onAnimationStart(@NonNull android.animation.Animator); } public static interface Animator.AnimatorPauseListener { - method public void onAnimationPause(android.animation.Animator); - method public void onAnimationResume(android.animation.Animator); + method public void onAnimationPause(@NonNull android.animation.Animator); + method public void onAnimationResume(@NonNull android.animation.Animator); } public class AnimatorInflater { @@ -3889,7 +3894,7 @@ package android.animation { } public static interface ValueAnimator.AnimatorUpdateListener { - method public void onAnimationUpdate(android.animation.ValueAnimator); + method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator); } } @@ -7329,6 +7334,8 @@ package android.app.admin { method public CharSequence getDeviceOwnerLockScreenInfo(); method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>); method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>); + method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon); + method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon); method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>); method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>); method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName); @@ -7933,8 +7940,7 @@ package android.app.admin { } public final class WifiSsidPolicy implements android.os.Parcelable { - method @NonNull public static android.app.admin.WifiSsidPolicy createAllowlistPolicy(@NonNull java.util.Set<android.net.wifi.WifiSsid>); - method @NonNull public static android.app.admin.WifiSsidPolicy createDenylistPolicy(@NonNull java.util.Set<android.net.wifi.WifiSsid>); + ctor public WifiSsidPolicy(int, @NonNull java.util.Set<android.net.wifi.WifiSsid>); method public int describeContents(); method public int getPolicyType(); method @NonNull public java.util.Set<android.net.wifi.WifiSsid> getSsids(); @@ -8594,62 +8600,6 @@ package android.app.usage { field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.ExternalStorageStats> CREATOR; } - public final class NetworkStats implements java.lang.AutoCloseable { - method public void close(); - method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket); - method public boolean hasNextBucket(); - } - - public static class NetworkStats.Bucket { - ctor public NetworkStats.Bucket(); - method public int getDefaultNetworkStatus(); - method public long getEndTimeStamp(); - method public int getMetered(); - method public int getRoaming(); - method public long getRxBytes(); - method public long getRxPackets(); - method public long getStartTimeStamp(); - method public int getState(); - method public int getTag(); - method public long getTxBytes(); - method public long getTxPackets(); - method public int getUid(); - field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff - field public static final int DEFAULT_NETWORK_NO = 1; // 0x1 - field public static final int DEFAULT_NETWORK_YES = 2; // 0x2 - field public static final int METERED_ALL = -1; // 0xffffffff - field public static final int METERED_NO = 1; // 0x1 - field public static final int METERED_YES = 2; // 0x2 - field public static final int ROAMING_ALL = -1; // 0xffffffff - field public static final int ROAMING_NO = 1; // 0x1 - field public static final int ROAMING_YES = 2; // 0x2 - field public static final int STATE_ALL = -1; // 0xffffffff - field public static final int STATE_DEFAULT = 1; // 0x1 - field public static final int STATE_FOREGROUND = 2; // 0x2 - field public static final int TAG_NONE = 0; // 0x0 - field public static final int UID_ALL = -1; // 0xffffffff - field public static final int UID_REMOVED = -4; // 0xfffffffc - field public static final int UID_TETHERING = -5; // 0xfffffffb - } - - public class NetworkStatsManager { - method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback); - method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler); - method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback); - } - - public abstract static class NetworkStatsManager.UsageCallback { - ctor public NetworkStatsManager.UsageCallback(); - method public abstract void onThresholdReached(int, String); - } - public final class StorageStats implements android.os.Parcelable { method public int describeContents(); method public long getAppBytes(); @@ -11931,7 +11881,7 @@ package android.content.pm { field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims"; field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms"; field public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging"; - field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio"; + field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access"; field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription"; field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television"; field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"; @@ -15768,9 +15718,9 @@ package android.graphics.drawable { method public final void copyBounds(@NonNull android.graphics.Rect); method @NonNull public final android.graphics.Rect copyBounds(); method @Nullable public static android.graphics.drawable.Drawable createFromPath(String); - method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, String); + method @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String); method @Deprecated @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String, @Nullable android.graphics.BitmapFactory.Options); - method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, String); + method @Nullable public static android.graphics.drawable.Drawable createFromStream(@Nullable java.io.InputStream, @Nullable String); method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method @NonNull public static android.graphics.drawable.Drawable createFromXmlInner(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; @@ -15808,10 +15758,10 @@ package android.graphics.drawable { method public final boolean isVisible(); method public void jumpToCurrentState(); method @NonNull public android.graphics.drawable.Drawable mutate(); - method protected void onBoundsChange(android.graphics.Rect); + method protected void onBoundsChange(@NonNull android.graphics.Rect); method public boolean onLayoutDirectionChanged(int); method protected boolean onLevelChange(int); - method protected boolean onStateChange(int[]); + method protected boolean onStateChange(@NonNull int[]); method public static int resolveOpacity(int, int); method public void scheduleSelf(@NonNull Runnable, long); method public abstract void setAlpha(@IntRange(from=0, to=255) int); @@ -15972,27 +15922,27 @@ package android.graphics.drawable { } public final class Icon implements android.os.Parcelable { - method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap); + method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap); method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull String); method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull android.net.Uri); - method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap); - method public static android.graphics.drawable.Icon createWithContentUri(String); - method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri); - method public static android.graphics.drawable.Icon createWithData(byte[], int, int); - method public static android.graphics.drawable.Icon createWithFilePath(String); - method public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int); - method public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int); + method @NonNull public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap); + method @NonNull public static android.graphics.drawable.Icon createWithContentUri(String); + method @NonNull public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri); + method @NonNull public static android.graphics.drawable.Icon createWithData(byte[], int, int); + method @NonNull public static android.graphics.drawable.Icon createWithFilePath(String); + method @NonNull public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int); + method @NonNull public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int); method public int describeContents(); method @DrawableRes public int getResId(); method @NonNull public String getResPackage(); method public int getType(); method @NonNull public android.net.Uri getUri(); - method public android.graphics.drawable.Drawable loadDrawable(android.content.Context); - method public void loadDrawableAsync(android.content.Context, android.os.Message); - method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler); - method public android.graphics.drawable.Icon setTint(@ColorInt int); + method @Nullable public android.graphics.drawable.Drawable loadDrawable(android.content.Context); + method public void loadDrawableAsync(@NonNull android.content.Context, @NonNull android.os.Message); + method public void loadDrawableAsync(@NonNull android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler); + method @NonNull public android.graphics.drawable.Icon setTint(@ColorInt int); method @NonNull public android.graphics.drawable.Icon setTintBlendMode(@NonNull android.graphics.BlendMode); - method public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList); + method @NonNull public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList); method @NonNull public android.graphics.drawable.Icon setTintMode(@NonNull android.graphics.PorterDuff.Mode); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR; @@ -16870,13 +16820,18 @@ package android.hardware { field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1 field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3 field public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer"; + field public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES = "android.sensor.accelerometer_limited_axes"; + field public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = "android.sensor.accelerometer_limited_axes_uncalibrated"; field public static final String STRING_TYPE_ACCELEROMETER_UNCALIBRATED = "android.sensor.accelerometer_uncalibrated"; field public static final String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature"; field public static final String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector"; field public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector"; field public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity"; field public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope"; + field public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES = "android.sensor.gyroscope_limited_axes"; + field public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = "android.sensor.gyroscope_limited_axes_uncalibrated"; field public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated"; + field public static final String STRING_TYPE_HEADING = "android.sensor.heading"; field public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker"; field public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat"; field public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate"; @@ -16899,6 +16854,8 @@ package android.hardware { field public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector"; field @Deprecated public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature"; field public static final int TYPE_ACCELEROMETER = 1; // 0x1 + field public static final int TYPE_ACCELEROMETER_LIMITED_AXES = 38; // 0x26 + field public static final int TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40; // 0x28 field public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35; // 0x23 field public static final int TYPE_ALL = -1; // 0xffffffff field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd @@ -16907,7 +16864,10 @@ package android.hardware { field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14 field public static final int TYPE_GRAVITY = 9; // 0x9 field public static final int TYPE_GYROSCOPE = 4; // 0x4 + field public static final int TYPE_GYROSCOPE_LIMITED_AXES = 39; // 0x27 + field public static final int TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41; // 0x29 field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10 + field public static final int TYPE_HEADING = 42; // 0x2a field public static final int TYPE_HEAD_TRACKER = 37; // 0x25 field public static final int TYPE_HEART_BEAT = 31; // 0x1f field public static final int TYPE_HEART_RATE = 21; // 0x15 @@ -17337,12 +17297,14 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION; @@ -17436,6 +17398,8 @@ package android.hardware.camera2 { } public final class CameraExtensionCharacteristics { + method @NonNull public java.util.Set<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(int); + method @NonNull public java.util.Set<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(int); method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRangeMillis(int, @NonNull android.util.Size, int); method @NonNull public <T> java.util.List<android.util.Size> getExtensionSupportedSizes(int, @NonNull Class<T>); method @NonNull public java.util.List<android.util.Size> getExtensionSupportedSizes(int, int); @@ -17460,6 +17424,7 @@ package android.hardware.camera2 { ctor public CameraExtensionSession.ExtensionCaptureCallback(); method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest); method public void onCaptureProcessStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest); + method public void onCaptureResultAvailable(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.TotalCaptureResult); method public void onCaptureSequenceAborted(@NonNull android.hardware.camera2.CameraExtensionSession, int); method public void onCaptureSequenceCompleted(@NonNull android.hardware.camera2.CameraExtensionSession, int); method public void onCaptureStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, long); @@ -17671,9 +17636,16 @@ package android.hardware.camera2 { field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5 field public static final int REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17; // 0x11 field public static final int REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13; // 0xd + field public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19; // 0x13 field public static final int REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14; // 0xe field public static final int REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR = 16; // 0x10 field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0; // 0x0 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 1; // 0x1 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 4; // 0x4 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 2; // 0x2 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 5; // 0x5 + field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 3; // 0x3 field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0 field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1 field public static final int SCALER_ROTATE_AND_CROP_180 = 2; // 0x2 @@ -18081,6 +18053,7 @@ package android.hardware.camera2.params { method public int get10BitFormat(); method @NonNull public java.util.List<android.util.Size> getAvailableSizes(); method public int getFormat(); + method public int getStreamUseCase(); method public boolean is10BitCapable(); method public boolean isInput(); method public boolean isMaximumSize(); @@ -18137,6 +18110,7 @@ package android.hardware.camera2.params { method public void enableSurfaceSharing(); method public int getDynamicRangeProfile(); method public int getMaxSharedSurfaceCount(); + method public int getStreamUseCase(); method @Nullable public android.view.Surface getSurface(); method public int getSurfaceGroupId(); method @NonNull public java.util.List<android.view.Surface> getSurfaces(); @@ -18144,6 +18118,7 @@ package android.hardware.camera2.params { method public void removeSurface(@NonNull android.view.Surface); method public void setDynamicRangeProfile(int); method public void setPhysicalCameraId(@Nullable String); + method public void setStreamUseCase(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR; field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff @@ -26526,50 +26501,6 @@ package android.net { method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int); } - public class TrafficStats { - ctor public TrafficStats(); - method public static void clearThreadStatsTag(); - method public static void clearThreadStatsUid(); - method public static int getAndSetThreadStatsTag(int); - method public static long getMobileRxBytes(); - method public static long getMobileRxPackets(); - method public static long getMobileTxBytes(); - method public static long getMobileTxPackets(); - method public static long getRxBytes(@NonNull String); - method public static long getRxPackets(@NonNull String); - method public static int getThreadStatsTag(); - method public static int getThreadStatsUid(); - method public static long getTotalRxBytes(); - method public static long getTotalRxPackets(); - method public static long getTotalTxBytes(); - method public static long getTotalTxPackets(); - method public static long getTxBytes(@NonNull String); - method public static long getTxPackets(@NonNull String); - method public static long getUidRxBytes(int); - method public static long getUidRxPackets(int); - method @Deprecated public static long getUidTcpRxBytes(int); - method @Deprecated public static long getUidTcpRxSegments(int); - method @Deprecated public static long getUidTcpTxBytes(int); - method @Deprecated public static long getUidTcpTxSegments(int); - method public static long getUidTxBytes(int); - method public static long getUidTxPackets(int); - method @Deprecated public static long getUidUdpRxBytes(int); - method @Deprecated public static long getUidUdpRxPackets(int); - method @Deprecated public static long getUidUdpTxBytes(int); - method @Deprecated public static long getUidUdpTxPackets(int); - method public static void incrementOperationCount(int); - method public static void incrementOperationCount(int, int); - method public static void setThreadStatsTag(int); - method public static void setThreadStatsUid(int); - method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException; - method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException; - method public static void tagSocket(java.net.Socket) throws java.net.SocketException; - method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException; - method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException; - method public static void untagSocket(java.net.Socket) throws java.net.SocketException; - field public static final int UNSUPPORTED = -1; // 0xffffffff - } - public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { method public abstract android.net.Uri.Builder buildUpon(); method public int compareTo(android.net.Uri); @@ -39376,6 +39307,7 @@ package android.speech { public interface RecognitionListener { method public void onBeginningOfSpeech(); method public void onBufferReceived(byte[]); + method public default void onEndOfSegmentedSession(); method public void onEndOfSpeech(); method public void onError(int); method public void onEvent(int, android.os.Bundle); @@ -39383,6 +39315,7 @@ package android.speech { method public void onReadyForSpeech(android.os.Bundle); method public void onResults(android.os.Bundle); method public void onRmsChanged(float); + method public default void onSegmentResults(@NonNull android.os.Bundle); } public abstract class RecognitionService extends android.app.Service { @@ -39400,6 +39333,7 @@ package android.speech { public class RecognitionService.Callback { method public void beginningOfSpeech() throws android.os.RemoteException; method public void bufferReceived(byte[]) throws android.os.RemoteException; + method public void endOfSegmentedSession() throws android.os.RemoteException; method public void endOfSpeech() throws android.os.RemoteException; method public void error(int) throws android.os.RemoteException; method @NonNull public android.content.AttributionSource getCallingAttributionSource(); @@ -39408,6 +39342,7 @@ package android.speech { method public void readyForSpeech(android.os.Bundle) throws android.os.RemoteException; method public void results(android.os.Bundle) throws android.os.RemoteException; method public void rmsChanged(float) throws android.os.RemoteException; + method public void segmentResults(@NonNull android.os.Bundle) throws android.os.RemoteException; } public static class RecognitionService.SupportCallback { @@ -39463,6 +39398,7 @@ package android.speech { field public static final String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT"; field public static final String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE"; field public static final String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE"; + field public static final String EXTRA_SEGMENT_SESSION = "android.speech.extra.SEGMENT_SESSION"; field public static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS"; field public static final String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS"; field public static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS"; @@ -43044,7 +42980,8 @@ package android.telephony { method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long); method public void setSubscriptionOverrideUnmetered(int, boolean, long); method public void setSubscriptionOverrideUnmetered(int, boolean, @NonNull int[], long); - method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>); + method @Deprecated public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>); + method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>, long); method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, @NonNull android.app.PendingIntent); field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED"; field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; @@ -43227,6 +43164,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot(); method public int getActiveModemCount(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getAllowedNetworkTypesForReason(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus(); method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public int getCallState(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCallStateForSubscription(); @@ -43287,6 +43225,7 @@ package android.telephony { method public int getSubscriptionId(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle); method public int getSupportedModemCount(); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getSupportedRadioAccessFamily(); method @Nullable public String getTypeAllocationCode(); method @Nullable public String getTypeAllocationCode(int); method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo(); @@ -43332,6 +43271,7 @@ package android.telephony { method public String sendEnvelopeWithStatus(String); method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean); @@ -43368,6 +43308,8 @@ package android.telephony { field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; field public static final String ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED"; + field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 + field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -43442,6 +43384,26 @@ package android.telephony { field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2 field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0 field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 + field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L + field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L + field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L + field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L + field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L + field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L + field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L + field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L + field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L + field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L + field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L + field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L + field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L + field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L + field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L + field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L + field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L + field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L + field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L + field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe @@ -48904,10 +48866,9 @@ package android.view { method public default void onBackInvoked(); } - public abstract class OnBackInvokedDispatcher { - ctor public OnBackInvokedDispatcher(); - method public abstract void registerOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback, int); - method public abstract void unregisterOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback); + public interface OnBackInvokedDispatcher { + method public void registerOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback, @IntRange(from=0) int); + method public void unregisterOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback); field public static final int PRIORITY_DEFAULT = 0; // 0x0 field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240 } @@ -51437,6 +51398,7 @@ package android.view.accessibility { method public CharSequence getPackageName(); method public android.view.accessibility.AccessibilityRecord getRecord(int); method public int getRecordCount(); + method public int getSpeechStateChangeTypes(); method public int getWindowChanges(); method public void initFromParcel(android.os.Parcel); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int); @@ -51448,6 +51410,7 @@ package android.view.accessibility { method public void setEventType(int); method public void setMovementGranularity(int); method public void setPackageName(CharSequence); + method public void setSpeechStateChangeTypes(int); method public void writeToParcel(android.os.Parcel, int); field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4 field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200 @@ -51463,12 +51426,17 @@ package android.view.accessibility { field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR; field public static final int INVALID_POSITION = -1; // 0xffffffff field @Deprecated public static final int MAX_TEXT_LENGTH = 500; // 0x1f4 + field public static final int SPEECH_STATE_LISTENING_END = 8; // 0x8 + field public static final int SPEECH_STATE_LISTENING_START = 4; // 0x4 + field public static final int SPEECH_STATE_SPEAKING_END = 2; // 0x2 + field public static final int SPEECH_STATE_SPEAKING_START = 1; // 0x1 field public static final int TYPES_ALL_MASK = -1; // 0xffffffff field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000 field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000 field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000 field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000 field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40 + field public static final int TYPE_SPEECH_STATE_CHANGE = 33554432; // 0x2000000 field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400 field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200 field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000 diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9737cde48b4d..36d54f59ed3f 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -86,31 +86,6 @@ package android.app.admin { } -package android.app.usage { - - public class NetworkStatsManager { - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void forceUpdate(); - method public static int getCollapsedRatType(int); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForDevice(@NonNull android.net.NetworkTemplate, long, long); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(@NonNull android.net.NetworkTemplate, long, long, int, int, int) throws java.lang.SecurityException; - method @NonNull @WorkerThread public android.app.usage.NetworkStats querySummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException; - method @NonNull @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(@NonNull android.net.NetworkTemplate, long, long); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryTaggedSummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException; - method public void registerUsageCallback(@NonNull android.net.NetworkTemplate, long, @NonNull java.util.concurrent.Executor, @NonNull android.app.usage.NetworkStatsManager.UsageCallback); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setDefaultGlobalAlert(long); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setStatsProviderWarningAndLimitAsync(@NonNull String, long, long); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setUidForeground(int, boolean); - field public static final int NETWORK_TYPE_5G_NSA = -2; // 0xfffffffe - } - - public abstract static class NetworkStatsManager.UsageCallback { - method public void onThresholdReached(@NonNull android.net.NetworkTemplate); - } - -} - package android.content { public abstract class ContentProvider implements android.content.ComponentCallbacks2 { @@ -287,32 +262,6 @@ package android.net { ctor public LocalSocket(@NonNull java.io.FileDescriptor); } - public class NetworkIdentity { - method public int getOemManaged(); - method public int getRatType(); - method @Nullable public String getSubscriberId(); - method public int getType(); - method @Nullable public String getWifiNetworkKey(); - method public boolean isDefaultNetwork(); - method public boolean isMetered(); - method public boolean isRoaming(); - } - - public static final class NetworkIdentity.Builder { - ctor public NetworkIdentity.Builder(); - method @NonNull public android.net.NetworkIdentity build(); - method @NonNull public android.net.NetworkIdentity.Builder clearRatType(); - method @NonNull public android.net.NetworkIdentity.Builder setDefaultNetwork(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setMetered(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setNetworkStateSnapshot(@NonNull android.net.NetworkStateSnapshot); - method @NonNull public android.net.NetworkIdentity.Builder setOemManaged(int); - method @NonNull public android.net.NetworkIdentity.Builder setRatType(int); - method @NonNull public android.net.NetworkIdentity.Builder setRoaming(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setSubscriberId(@Nullable String); - method @NonNull public android.net.NetworkIdentity.Builder setType(int); - method @NonNull public android.net.NetworkIdentity.Builder setWifiNetworkKey(@Nullable String); - } - public class NetworkPolicyManager { method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int); @@ -328,94 +277,6 @@ package android.net { method public default void onUidBlockedReasonChanged(int, int); } - public final class NetworkStateSnapshot implements android.os.Parcelable { - ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int); - method public int describeContents(); - method public int getLegacyType(); - method @NonNull public android.net.LinkProperties getLinkProperties(); - method @NonNull public android.net.Network getNetwork(); - method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); - method @Nullable public String getSubscriberId(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR; - } - - public class NetworkStatsCollection { - method @NonNull public java.util.Map<android.net.NetworkStatsCollection.Key,android.net.NetworkStatsHistory> getEntries(); - } - - public static final class NetworkStatsCollection.Builder { - ctor public NetworkStatsCollection.Builder(long); - method @NonNull public android.net.NetworkStatsCollection.Builder addEntry(@NonNull android.net.NetworkStatsCollection.Key, @NonNull android.net.NetworkStatsHistory); - method @NonNull public android.net.NetworkStatsCollection build(); - } - - public static class NetworkStatsCollection.Key { - ctor public NetworkStatsCollection.Key(@NonNull java.util.Set<android.net.NetworkIdentity>, int, int, int); - } - - public final class NetworkStatsHistory implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.List<android.net.NetworkStatsHistory.Entry> getEntries(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStatsHistory> CREATOR; - } - - public static final class NetworkStatsHistory.Builder { - ctor public NetworkStatsHistory.Builder(long, int); - method @NonNull public android.net.NetworkStatsHistory.Builder addEntry(@NonNull android.net.NetworkStatsHistory.Entry); - method @NonNull public android.net.NetworkStatsHistory build(); - } - - public static final class NetworkStatsHistory.Entry { - ctor public NetworkStatsHistory.Entry(long, long, long, long, long, long, long); - method public long getActiveTime(); - method public long getBucketStart(); - method public long getOperations(); - method public long getRxBytes(); - method public long getRxPackets(); - method public long getTxBytes(); - method public long getTxPackets(); - } - - public final class NetworkTemplate implements android.os.Parcelable { - method public int describeContents(); - method public int getDefaultNetworkStatus(); - method public int getMatchRule(); - method public int getMeteredness(); - method public int getOemManaged(); - method public int getRatType(); - method public int getRoaming(); - method @NonNull public java.util.Set<java.lang.String> getSubscriberIds(); - method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys(); - method public boolean matches(@NonNull android.net.NetworkIdentity); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR; - field public static final int MATCH_BLUETOOTH = 8; // 0x8 - field public static final int MATCH_CARRIER = 10; // 0xa - field public static final int MATCH_ETHERNET = 5; // 0x5 - field public static final int MATCH_MOBILE = 1; // 0x1 - field public static final int MATCH_WIFI = 4; // 0x4 - field public static final int NETWORK_TYPE_ALL = -1; // 0xffffffff - field public static final int OEM_MANAGED_ALL = -1; // 0xffffffff - field public static final int OEM_MANAGED_NO = 0; // 0x0 - field public static final int OEM_MANAGED_PAID = 1; // 0x1 - field public static final int OEM_MANAGED_PRIVATE = 2; // 0x2 - field public static final int OEM_MANAGED_YES = -2; // 0xfffffffe - } - - public static final class NetworkTemplate.Builder { - ctor public NetworkTemplate.Builder(int); - method @NonNull public android.net.NetworkTemplate build(); - method @NonNull public android.net.NetworkTemplate.Builder setDefaultNetworkStatus(int); - method @NonNull public android.net.NetworkTemplate.Builder setMeteredness(int); - method @NonNull public android.net.NetworkTemplate.Builder setOemManaged(int); - method @NonNull public android.net.NetworkTemplate.Builder setRatType(int); - method @NonNull public android.net.NetworkTemplate.Builder setRoaming(int); - method @NonNull public android.net.NetworkTemplate.Builder setSubscriberIds(@NonNull java.util.Set<java.lang.String>); - method @NonNull public android.net.NetworkTemplate.Builder setWifiNetworkKeys(@NonNull java.util.Set<java.lang.String>); - } - public class NetworkWatchlistManager { method @Nullable public byte[] getWatchlistConfigHash(); } @@ -434,21 +295,6 @@ package android.net { method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); } - public class TrafficStats { - method public static void attachSocketTagger(); - method public static void init(@NonNull android.content.Context); - } - - public final class UnderlyingNetworkInfo implements android.os.Parcelable { - ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>); - method public int describeContents(); - method @NonNull public String getInterface(); - method public int getOwnerUid(); - method @NonNull public java.util.List<java.lang.String> getUnderlyingInterfaces(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR; - } - public class VpnManager { field public static final int TYPE_VPN_LEGACY = 3; // 0x3 field public static final int TYPE_VPN_NONE = -1; // 0xffffffff diff --git a/core/api/removed.txt b/core/api/removed.txt index 07639fbf5378..608a9a4efeca 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -250,10 +250,6 @@ package android.net { method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache); } - public class TrafficStats { - method @Deprecated public static void setThreadStatsUidSelf(); - } - } package android.os { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index a97ccc91d1ff..0349f044719f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2260,9 +2260,9 @@ package android.app.smartspace.uitemplatedata { public static final class SmartspaceCarouselUiTemplateData.CarouselItem implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getImage(); - method @Nullable public CharSequence getLowerText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getLowerText(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getTapAction(); - method @Nullable public CharSequence getUpperText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getUpperText(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem> CREATOR; } @@ -2271,9 +2271,9 @@ package android.app.smartspace.uitemplatedata { ctor public SmartspaceCarouselUiTemplateData.CarouselItem.Builder(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem build(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setImage(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setLowerText(@Nullable CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setLowerText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setTapAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setUpperText(@Nullable CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setUpperText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText); } public final class SmartspaceCombinedCardsUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData { @@ -2289,15 +2289,15 @@ package android.app.smartspace.uitemplatedata { public class SmartspaceDefaultUiTemplateData implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getPrimaryTapAction(); - method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubTitleIcon(); - method @Nullable public CharSequence getSubtitleText(); - method @Nullable public CharSequence getSupplementalAlarmText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubtitleIcon(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubtitleText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalAlarmText(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSupplementalSubtitleIcon(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSupplementalSubtitleTapAction(); - method @Nullable public CharSequence getSupplementalSubtitleText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalSubtitleText(); method public int getTemplateType(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getTitleIcon(); - method @Nullable public CharSequence getTitleText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getTitleText(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData> CREATOR; } @@ -2306,23 +2306,23 @@ package android.app.smartspace.uitemplatedata { ctor public SmartspaceDefaultUiTemplateData.Builder(int); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData build(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setPrimaryTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubTitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleText(@NonNull CharSequence); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalAlarmText(@NonNull CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalAlarmText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleText(@NonNull CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleText(@NonNull CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText); } public final class SmartspaceHeadToHeadUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData { method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getHeadToHeadAction(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadFirstCompetitorIcon(); - method @Nullable public CharSequence getHeadToHeadFirstCompetitorText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadFirstCompetitorText(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadSecondCompetitorIcon(); - method @Nullable public CharSequence getHeadToHeadSecondCompetitorText(); - method @Nullable public CharSequence getHeadToHeadTitle(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadSecondCompetitorText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadTitle(); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData> CREATOR; } @@ -2331,16 +2331,17 @@ package android.app.smartspace.uitemplatedata { method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData build(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable CharSequence); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadTitle(@Nullable CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadTitle(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText); } public final class SmartspaceIcon implements android.os.Parcelable { method public int describeContents(); method @Nullable public CharSequence getContentDescription(); method @NonNull public android.graphics.drawable.Icon getIcon(); + method public boolean shouldTint(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceIcon> CREATOR; } @@ -2349,46 +2350,47 @@ package android.app.smartspace.uitemplatedata { ctor public SmartspaceIcon.Builder(@NonNull android.graphics.drawable.Icon); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon build(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setContentDescription(@NonNull CharSequence); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setShouldTint(boolean); } public final class SmartspaceSubCardUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData { method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubCardAction(); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubCardIcon(); - method @Nullable public CharSequence getSubCardText(); + method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubCardText(); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData> CREATOR; } public static final class SmartspaceSubCardUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder { ctor public SmartspaceSubCardUiTemplateData.Builder(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData build(); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardAction(@NonNull CharSequence); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText); } public final class SmartspaceSubImageUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData { method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubImageAction(); - method @NonNull public java.util.List<java.lang.CharSequence> getSubImageTexts(); + method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubImageTexts(); method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon> getSubImages(); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData> CREATOR; } public static final class SmartspaceSubImageUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder { - ctor public SmartspaceSubImageUiTemplateData.Builder(@NonNull java.util.List<java.lang.CharSequence>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon>); + ctor public SmartspaceSubImageUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon>); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData build(); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData.Builder setSubImageAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); } public final class SmartspaceSubListUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData { method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubListAction(); method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubListIcon(); - method @NonNull public java.util.List<java.lang.CharSequence> getSubListTexts(); + method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubListTexts(); field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData> CREATOR; } public static final class SmartspaceSubListUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder { - ctor public SmartspaceSubListUiTemplateData.Builder(@NonNull java.util.List<java.lang.CharSequence>); + ctor public SmartspaceSubListUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData build(); - method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction); method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon); } @@ -2412,6 +2414,21 @@ package android.app.smartspace.uitemplatedata { method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setUserHandle(@Nullable android.os.UserHandle); } + public final class SmartspaceText implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public CharSequence getText(); + method @NonNull public android.text.TextUtils.TruncateAt getTruncateAtType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceText> CREATOR; + } + + public static final class SmartspaceText.Builder { + ctor public SmartspaceText.Builder(@NonNull CharSequence); + ctor public SmartspaceText.Builder(@NonNull CharSequence, @NonNull android.text.TextUtils.TruncateAt); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText build(); + method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText.Builder setTruncateAtType(@NonNull android.text.TextUtils.TruncateAt); + } + } package android.app.time { @@ -2521,13 +2538,6 @@ package android.app.usage { field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService"; } - public class NetworkStatsManager { - method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getMobileUidStats(); - method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getWifiUidStats(); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider); - } - public static final class UsageEvents.Event { method public int getInstanceId(); method @Nullable public String getNotificationChannelId(); @@ -8420,48 +8430,6 @@ package android.net { field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; } - public final class NetworkStats implements java.lang.Iterable<android.net.NetworkStats.Entry> android.os.Parcelable { - ctor public NetworkStats(long, int); - method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats); - method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry); - method public int describeContents(); - method @NonNull public java.util.Iterator<android.net.NetworkStats.Entry> iterator(); - method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR; - field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff - field public static final int DEFAULT_NETWORK_NO = 0; // 0x0 - field public static final int DEFAULT_NETWORK_YES = 1; // 0x1 - field public static final String IFACE_VT = "vt_data0"; - field public static final int METERED_ALL = -1; // 0xffffffff - field public static final int METERED_NO = 0; // 0x0 - field public static final int METERED_YES = 1; // 0x1 - field public static final int ROAMING_ALL = -1; // 0xffffffff - field public static final int ROAMING_NO = 0; // 0x0 - field public static final int ROAMING_YES = 1; // 0x1 - field public static final int SET_ALL = -1; // 0xffffffff - field public static final int SET_DEFAULT = 0; // 0x0 - field public static final int SET_FOREGROUND = 1; // 0x1 - field public static final int TAG_NONE = 0; // 0x0 - field public static final int UID_ALL = -1; // 0xffffffff - field public static final int UID_TETHERING = -5; // 0xfffffffb - } - - public static class NetworkStats.Entry { - ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long); - method public int getDefaultNetwork(); - method public int getMetered(); - method public long getOperations(); - method public int getRoaming(); - method public long getRxBytes(); - method public long getRxPackets(); - method public int getSet(); - method public int getTag(); - method public long getTxBytes(); - method public long getTxPackets(); - method public int getUid(); - } - @Deprecated public class RssiCurve implements android.os.Parcelable { ctor @Deprecated public RssiCurve(int, int, byte[]); ctor @Deprecated public RssiCurve(int, int, byte[], int); @@ -8493,19 +8461,6 @@ package android.net { field @Deprecated public final android.net.RssiCurve rssiCurve; } - public class TrafficStats { - method public static void setThreadStatsTagApp(); - method public static void setThreadStatsTagBackup(); - method public static void setThreadStatsTagDownload(); - method public static void setThreadStatsTagRestore(); - field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f - field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80 - field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff - field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00 - field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f - field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00 - } - public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { method @NonNull public String toSafeString(); } @@ -8686,23 +8641,6 @@ package android.net.metrics { } -package android.net.netstats.provider { - - public abstract class NetworkStatsProvider { - ctor public NetworkStatsProvider(); - method public void notifyAlertReached(); - method public void notifyLimitReached(); - method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); - method public void notifyWarningReached(); - method public abstract void onRequestStatsUpdate(int); - method public abstract void onSetAlert(long); - method public abstract void onSetLimit(@NonNull String, long); - method public void onSetWarningAndLimit(@NonNull String, long, long); - field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff - } - -} - package android.net.sip { @Deprecated public class SipAudioCall { @@ -9674,7 +9612,7 @@ package android.os { method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles(); method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String, boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getRestrictedProfileParent(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName(); @@ -10420,8 +10358,6 @@ package android.provider { } public static final class Settings.Secure extends android.provider.Settings.NameValueTable { - method public static int getIntForUser(@NonNull android.content.ContentResolver, @NonNull String, int, int); - method @Nullable public static String getStringForUser(@NonNull android.content.ContentResolver, @NonNull String, int); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String); field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled"; @@ -11145,6 +11081,7 @@ package android.service.euicc { field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT"; field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; + field public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID"; field public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX"; field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS"; field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1 @@ -13208,7 +13145,6 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesBitmask(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesForReason(int); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); @@ -13254,7 +13190,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Collection<android.telephony.UiccSlotMapping> getSimSlotMapping(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telephony.RadioAccessSpecifier> getSystemSelectionChannels(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo(); @@ -13309,7 +13244,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); @@ -13359,10 +13293,8 @@ package android.telephony { field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; - field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3 field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1 - field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2 field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1 field public static final int CALL_WAITING_STATUS_FDN_CHECK_FAILURE = 5; // 0x5 @@ -13402,26 +13334,6 @@ package android.telephony { field public static final int KEY_TYPE_WLAN = 2; // 0x2 field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1 field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2 - field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L - field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L - field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L - field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L - field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L - field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L - field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L - field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L - field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L - field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L - field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L - field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L - field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L - field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L - field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L - field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L - field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L - field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L - field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L - field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2 field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3 field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 9d6fc0e67f03..4132c64a44c9 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -511,6 +511,8 @@ package android.app.admin { field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED"; field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED"; field @Deprecated public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe + field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0 + field public static final int DEVICE_OWNER_TYPE_FINANCED = 1; // 0x1 field public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23; // 0x17 field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5 field public static final int OPERATION_INSTALL_CA_CERT = 24; // 0x18 @@ -614,10 +616,6 @@ package android.app.prediction { package android.app.usage { - public class NetworkStatsManager { - method public void setPollForce(boolean); - } - public class StorageStatsManager { method public boolean isQuotaSupported(@NonNull java.util.UUID); method public boolean isReservedSupported(@NonNull java.util.UUID); @@ -668,6 +666,7 @@ package android.content { ctor public AttributionSource(int, @Nullable String, @Nullable String); ctor public AttributionSource(int, @Nullable String, @Nullable String, @NonNull android.os.IBinder); ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable java.util.Set<java.lang.String>, @Nullable android.content.AttributionSource); + method public void enforceCallingPid(); } public final class AutofillOptions implements android.os.Parcelable { @@ -985,7 +984,7 @@ package android.database.sqlite { package android.graphics { public final class ImageDecoder implements java.lang.AutoCloseable { - method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int); + method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, @NonNull java.io.InputStream, int); } public final class Rect implements android.os.Parcelable { @@ -1623,13 +1622,6 @@ package android.net { method @Nullable public byte[] getWatchlistConfigHash(); } - public class TrafficStats { - method public static long getLoopbackRxBytes(); - method public static long getLoopbackRxPackets(); - method public static long getLoopbackTxBytes(); - method public static long getLoopbackTxPackets(); - } - } package android.os { @@ -2518,7 +2510,6 @@ package android.telephony { method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily(); method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); @@ -2800,6 +2791,10 @@ package android.view { field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 } + public interface OnBackInvokedDispatcher { + field public static final long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; // 0xbade858L + } + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod { method public abstract String asyncImpl() default ""; } diff --git a/core/java/Android.bp b/core/java/Android.bp index edf9ece4661c..a5526bc66431 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -160,7 +160,6 @@ java_library { filegroup { name: "framework-services-net-module-wifi-shared-srcs", srcs: [ - "android/net/DhcpResults.java", "android/util/LocalLog.java", ], } diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index eb525d301986..a8ff36aae098 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -16,6 +16,7 @@ package android.animation; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; @@ -535,7 +536,7 @@ public abstract class Animator implements Cloneable { * @param animation The started animation. * @param isReverse Whether the animation is playing in reverse. */ - default void onAnimationStart(Animator animation, boolean isReverse) { + default void onAnimationStart(@NonNull Animator animation, boolean isReverse) { onAnimationStart(animation); } @@ -551,7 +552,7 @@ public abstract class Animator implements Cloneable { * @param animation The animation which reached its end. * @param isReverse Whether the animation is playing in reverse. */ - default void onAnimationEnd(Animator animation, boolean isReverse) { + default void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { onAnimationEnd(animation); } @@ -560,7 +561,7 @@ public abstract class Animator implements Cloneable { * * @param animation The started animation. */ - void onAnimationStart(Animator animation); + void onAnimationStart(@NonNull Animator animation); /** * <p>Notifies the end of the animation. This callback is not invoked @@ -568,7 +569,7 @@ public abstract class Animator implements Cloneable { * * @param animation The animation which reached its end. */ - void onAnimationEnd(Animator animation); + void onAnimationEnd(@NonNull Animator animation); /** * <p>Notifies the cancellation of the animation. This callback is not invoked @@ -576,14 +577,14 @@ public abstract class Animator implements Cloneable { * * @param animation The animation which was canceled. */ - void onAnimationCancel(Animator animation); + void onAnimationCancel(@NonNull Animator animation); /** * <p>Notifies the repetition of the animation.</p> * * @param animation The animation which was repeated. */ - void onAnimationRepeat(Animator animation); + void onAnimationRepeat(@NonNull Animator animation); } /** @@ -599,7 +600,7 @@ public abstract class Animator implements Cloneable { * @param animation The animaton being paused. * @see #pause() */ - void onAnimationPause(Animator animation); + void onAnimationPause(@NonNull Animator animation); /** * <p>Notifies that the animation was resumed, after being @@ -608,7 +609,7 @@ public abstract class Animator implements Cloneable { * @param animation The animation being resumed. * @see #resume() */ - void onAnimationResume(Animator animation); + void onAnimationResume(@NonNull Animator animation); } /** diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 3cbae99224c7..06b424bcb417 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -18,6 +18,7 @@ package android.animation; import android.annotation.CallSuper; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -1626,7 +1627,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * * @param animation The animation which was repeated. */ - void onAnimationUpdate(ValueAnimator animation); + void onAnimationUpdate(@NonNull ValueAnimator animation); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 8935022639e4..db865ced6a67 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -115,6 +115,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.OnBackInvokedCallback; import android.view.OnBackInvokedDispatcher; import android.view.OnBackInvokedDispatcherOwner; import android.view.RemoteAnimationDefinition; @@ -144,6 +145,7 @@ import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; import android.window.SplashScreen; +import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -791,6 +793,7 @@ public class Activity extends ContextThemeWrapper private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062; private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064; private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065; + private OnBackInvokedCallback mDefaultBackCallback; /** * After {@link Build.VERSION_CODES#TIRAMISU}, @@ -1617,7 +1620,16 @@ public class Activity extends ContextThemeWrapper } mRestoredFromBundle = savedInstanceState != null; mCalled = true; - + if (!WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) { + // Add onBackPressed as default back behavior. + mDefaultBackCallback = new OnBackInvokedCallback() { + @Override + public void onBackInvoked() { + navigateBack(); + } + }; + getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback); + } } /** @@ -2653,6 +2665,10 @@ public class Activity extends ContextThemeWrapper if (mUiTranslationController != null) { mUiTranslationController.onActivityDestroyed(); } + + if (mDefaultBackCallback != null) { + getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback); + } } /** @@ -3773,10 +3789,13 @@ public class Activity extends ContextThemeWrapper * @see KeyEvent */ public boolean onKeyUp(int keyCode, KeyEvent event) { - if (getApplicationInfo().targetSdkVersion - >= Build.VERSION_CODES.ECLAIR) { - if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() - && !event.isCanceled()) { + int sdkVersion = getApplicationInfo().targetSdkVersion; + if (sdkVersion >= Build.VERSION_CODES.ECLAIR) { + if (keyCode == KeyEvent.KEYCODE_BACK + && event.isTracking() + && !event.isCanceled() + && mDefaultBackCallback == null) { + // Using legacy back handling. onBackPressed(); return true; } @@ -3841,6 +3860,10 @@ public class Activity extends ContextThemeWrapper if (!fragmentManager.isStateSaved() && fragmentManager.popBackStackImmediate()) { return; } + navigateBack(); + } + + private void navigateBack() { if (!isTaskRoot()) { // If the activity is not the root of the task, allow finish to proceed normally. finishAfterTransition(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fdf37f6633ee..0d1bc05df67b 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2363,11 +2363,11 @@ public class AppOpsManager { Manifest.permission.USE_BIOMETRIC, Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.SMS_FINANCIAL_TRANSACTIONS, - null, + Manifest.permission.READ_MEDIA_AUDIO, null, // no permission for OP_WRITE_MEDIA_AUDIO - null, + Manifest.permission.READ_MEDIA_VIDEO, null, // no permission for OP_WRITE_MEDIA_VIDEO - null, + Manifest.permission.READ_MEDIA_IMAGE, null, // no permission for OP_WRITE_MEDIA_IMAGES null, // no permission for OP_LEGACY_STORAGE null, // no permission for OP_ACCESS_ACCESSIBILITY diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 4b42ddc383b2..208477588885 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -52,6 +52,7 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.OnBackInvokedCallback; import android.view.OnBackInvokedDispatcher; import android.view.OnBackInvokedDispatcherOwner; import android.view.SearchEvent; @@ -62,6 +63,7 @@ import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.R; import com.android.internal.app.WindowDecorActionBar; @@ -156,6 +158,7 @@ public class Dialog implements DialogInterface, Window.Callback, /** A {@link Runnable} to run instead of dismissing when {@link #dismiss()} is called. */ private Runnable mDismissOverride; + private OnBackInvokedCallback mDefaultBackCallback; /** * Creates a dialog window that uses the default dialog theme. @@ -453,6 +456,16 @@ public class Dialog implements DialogInterface, Window.Callback, */ protected void onStart() { if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true); + if (mContext != null && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) { + // Add onBackPressed as default back behavior. + mDefaultBackCallback = new OnBackInvokedCallback() { + @Override + public void onBackInvoked() { + onBackPressed(); + } + }; + getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback); + } } /** @@ -460,6 +473,9 @@ public class Dialog implements DialogInterface, Window.Callback, */ protected void onStop() { if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); + if (mDefaultBackCallback != null) { + getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback); + } } private static final String DIALOG_SHOWING_TAG = "android:dialogShowing"; @@ -685,7 +701,8 @@ public class Dialog implements DialogInterface, Window.Callback, public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) && event.isTracking() - && !event.isCanceled()) { + && !event.isCanceled() + && WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) { onBackPressed(); return true; } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index eb4585dd7097..a74438ae8452 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -376,14 +376,16 @@ public class Instrumentation { Debug.stopMethodTracing(); } } - + /** - * Force the global system in or out of touch mode. This can be used if - * your instrumentation relies on the UI being in one more or the other - * when it starts. - * - * @param inTouch Set to true to be in touch mode, false to be in - * focus mode. + * Force the global system in or out of touch mode. This can be used if your + * instrumentation relies on the UI being in one more or the other when it starts. + * + * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method + * will only have an effect if the calling process is also the focused window owner or has + * {@link android.permission#MODIFY_TOUCH_MODE_STATE} permission granted. + * + * @param inTouch Set to true to be in touch mode, false to be in focus mode. */ public void setInTouchMode(boolean inTouch) { try { @@ -393,11 +395,11 @@ public class Instrumentation { // Shouldn't happen! } } - + /** * Schedule a callback for when the application's main thread goes idle * (has no more events to process). - * + * * @param recipient Called the next time the thread's message queue is * idle. */ diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 8fcb07f578e8..da1ba5265c4a 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -180,6 +180,8 @@ public class StatusBarManager { public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0; /** @hide */ public static final int NAVIGATION_HINT_IME_SHOWN = 1 << 1; + /** @hide */ + public static final int NAVIGATION_HINT_IME_SWITCHER_SHOWN = 1 << 2; /** @hide */ public static final int WINDOW_STATUS_BAR = 1; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 4187ba0a10a5..f5f2fe0d0292 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -48,7 +48,6 @@ import android.app.timezonedetector.TimeZoneDetectorImpl; import android.app.trust.TrustManager; import android.app.usage.IStorageStatsManager; import android.app.usage.IUsageStatsManager; -import android.app.usage.NetworkStatsManager; import android.app.usage.StorageStatsManager; import android.app.usage.UsageStatsManager; import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager; @@ -140,7 +139,6 @@ import android.net.ConnectivityFrameworkInitializerTiramisu; import android.net.EthernetManager; import android.net.IEthernetManager; import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.IPacProxyManager; import android.net.IVpnManager; import android.net.NetworkPolicyManager; @@ -1013,17 +1011,6 @@ public final class SystemServiceRegistry { return new UsageStatsManager(ctx.getOuterContext(), service); }}); - registerService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class, - new CachedServiceFetcher<NetworkStatsManager>() { - @Override - public NetworkStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException { - // TODO: Replace with an initializer in the module, see - // {@code ConnectivityFrameworkInitializer}. - final INetworkStatsService service = INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); - return new NetworkStatsManager(ctx.getOuterContext(), service); - }}); - registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class, new StaticServiceFetcher<PersistentDataBlockManager>() { @Override diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4704a24d2ca5..108412db7208 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -56,6 +56,7 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.net.PrivateDnsConnectivityChecker; import android.net.ProxyInfo; import android.net.Uri; @@ -465,7 +466,9 @@ public class DevicePolicyManager { * <li>{@link #setUserControlDisabledPackages(ComponentName, List)}</li> * <li>{@link #getUserControlDisabledPackages(ComponentName)}</li> * <li>{@link #setOrganizationName(ComponentName, CharSequence)}</li> + * <li>{@link #getOrganizationName(ComponentName)} </li> * <li>{@link #setShortSupportMessage(ComponentName, CharSequence)}</li> + * <li>{@link #getShortSupportMessage(ComponentName)}</li> * <li>{@link #isBackupServiceEnabled(ComponentName)}</li> * <li>{@link #setBackupServiceEnabled(ComponentName, boolean)}</li> * <li>{@link #isLockTaskPermitted(String)}</li> @@ -478,7 +481,9 @@ public class DevicePolicyManager { * <li>{@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}</li> * <li>{@link #LOCK_TASK_FEATURE_NOTIFICATIONS}</li> * </ul> + * <li>{@link #getLockTaskFeatures(ComponentName)}</li> * <li>{@link #setLockTaskPackages(ComponentName, String[])}</li> + * <li>{@link #getLockTaskPackages(ComponentName)}</li> * <li>{@link #addPersistentPreferredActivity(ComponentName, IntentFilter, ComponentName)}</li> * <li>{@link #clearPackagePersistentPreferredActivities(ComponentName, String)} </li> * <li>{@link #wipeData(int)}</li> @@ -489,6 +494,10 @@ public class DevicePolicyManager { * {@link #PERMISSION_GRANT_STATE_GRANTED}, {@link #PERMISSION_GRANT_STATE_DENIED}, or * {@link #PERMISSION_GRANT_STATE_DEFAULT} and can <b>only</b> be applied to the device admin * app (otherwise a {@link SecurityException} will be thrown)</li> + * <li>{@link #getPermissionGrantState(ComponentName, String, String)}, where + * {@link permission#READ_PHONE_STATE} is the <b>only</b> permission that can be + * used and device admin app is the only package that can be used to retrieve the permission + * permission grant state for (otherwise a {@link SecurityException} will be thrown)</li> * <li>{@link #addUserRestriction(ComponentName, String)}, where the following user restrictions * are permitted (otherwise a {@link SecurityException} will be thrown):</li> * <ul> @@ -499,7 +508,17 @@ public class DevicePolicyManager { * <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li> * <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li> * </ul> - * <li>{@link #clearUserRestriction(ComponentName, String)}</li> + * <li>{@link #getUserRestrictions(ComponentName)}</li> + * <li>{@link #clearUserRestriction(ComponentName, String)}, where the following user + * restrictions are permitted (otherwise a {@link SecurityException} will be thrown):</li> + * <ul> + * <li>{@link UserManager#DISALLOW_ADD_USER}</li> + * <li>{@link UserManager#DISALLOW_DEBUGGING_FEATURES}</li> + * <li>{@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES}</li> + * <li>{@link UserManager#DISALLOW_SAFE_BOOT}</li> + * <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li> + * <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li> + * </ul> * </ul> * * @hide @@ -3259,6 +3278,7 @@ public class DevicePolicyManager { * * @hide */ + @TestApi public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; /** @@ -3266,6 +3286,7 @@ public class DevicePolicyManager { * * @hide */ + @TestApi public static final int DEVICE_OWNER_TYPE_FINANCED = 1; /** @@ -14949,7 +14970,8 @@ public class DevicePolicyManager { wifiSsidAllowlist.add( WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8))); } - return WifiSsidPolicy.createAllowlistPolicy(new ArraySet<>(wifiSsidAllowlist)); + return new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, + new ArraySet<>(wifiSsidAllowlist)); } List<String> denylist = mService.getSsidDenylist(); if (!denylist.isEmpty()) { @@ -14958,7 +14980,8 @@ public class DevicePolicyManager { wifiSsidDenylist.add( WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8))); } - return WifiSsidPolicy.createDenylistPolicy(new ArraySet<>(wifiSsidDenylist)); + return new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, + new ArraySet<>(wifiSsidDenylist)); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -15222,6 +15245,66 @@ public class DevicePolicyManager { } /** + * Similar to {@link #getDrawable(String, String, String, Callable)} but returns an + * {@link Icon} instead of a {@link Drawable}. + * + * @param drawableId The drawable ID to get the updated resource for. + * @param drawableStyle The drawable style to use. + * @param drawableSource The source for the caller. + * @param defaultIcon Returned if no updated drawable was set for the provided params. + */ + @Nullable + public Icon getDrawableAsIcon( + @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId, + @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle, + @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource, + @Nullable Icon defaultIcon) { + Objects.requireNonNull(drawableId, "drawableId can't be null"); + Objects.requireNonNull(drawableStyle, "drawableStyle can't be null"); + Objects.requireNonNull(drawableSource, "drawableSource can't be null"); + Objects.requireNonNull(defaultIcon, "defaultIcon can't be null"); + + if (Drawables.UNDEFINED.equals(drawableId)) { + return defaultIcon; + } + if (mService != null) { + try { + ParcelableResource resource = mService.getDrawable( + drawableId, drawableStyle, drawableSource); + if (resource == null) { + return defaultIcon; + } + return Icon.createWithResource(resource.getPackageName(), resource.getResourceId()); + } catch (RemoteException e) { + Log.e( + TAG, + "Error getting the updated drawable from DevicePolicyManagerService.", + e); + return defaultIcon; + } + } + return defaultIcon; + } + + /** + * Similar to {@link #getDrawable(String, String, Callable)} but returns an {@link Icon} + * instead of a {@link Drawable}. + * + * @param drawableId The drawable ID to get the updated resource for. + * @param drawableStyle The drawable style to use. + * @param defaultIcon Returned if no updated drawable was set for the provided params. + */ + @Nullable + public Icon getDrawableAsIcon( + @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId, + @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle, + @Nullable Icon defaultIcon) { + return getDrawableAsIcon( + drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultIcon); + } + + + /** * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID * {@code callingPackageResourceId} (see {@link DevicePolicyResources.Strings}), meaning any diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java index a7046d41704a..e91807535c6e 100644 --- a/core/java/android/app/admin/WifiSsidPolicy.java +++ b/core/java/android/app/admin/WifiSsidPolicy.java @@ -73,41 +73,28 @@ public final class WifiSsidPolicy implements Parcelable { private @WifiSsidPolicyType int mPolicyType; private ArraySet<WifiSsid> mSsids; - private WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<WifiSsid> ssids) { - mPolicyType = policyType; - mSsids = new ArraySet<>(ssids); - } - - private WifiSsidPolicy(Parcel in) { - mPolicyType = in.readInt(); - mSsids = (ArraySet<WifiSsid>) in.readArraySet(null); - } /** - * Create the allowlist Wi-Fi SSID Policy. + * Create the Wi-Fi SSID Policy. * - * @param ssids allowlist of {@link WifiSsid} - * @throws IllegalArgumentException if the input ssids list is empty + * @param policyType indicate whether the policy is an allowlist or a denylist + * @param ssids set of {@link WifiSsid} + * @throws IllegalArgumentException if the input ssids set is empty or the policyType is invalid */ - @NonNull - public static WifiSsidPolicy createAllowlistPolicy(@NonNull Set<WifiSsid> ssids) { + public WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<WifiSsid> ssids) { if (ssids.isEmpty()) { throw new IllegalArgumentException("SSID list cannot be empty"); } - return new WifiSsidPolicy(WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids); + if (policyType != WIFI_SSID_POLICY_TYPE_ALLOWLIST + && policyType != WIFI_SSID_POLICY_TYPE_DENYLIST) { + throw new IllegalArgumentException("Invalid policy type"); + } + mPolicyType = policyType; + mSsids = new ArraySet<>(ssids); } - /** - * Create the denylist Wi-Fi SSID Policy. - * - * @param ssids denylist of {@link WifiSsid} - * @throws IllegalArgumentException if the input ssids list is empty - */ - @NonNull - public static WifiSsidPolicy createDenylistPolicy(@NonNull Set<WifiSsid> ssids) { - if (ssids.isEmpty()) { - throw new IllegalArgumentException("SSID list cannot be empty"); - } - return new WifiSsidPolicy(WIFI_SSID_POLICY_TYPE_DENYLIST, ssids); + private WifiSsidPolicy(Parcel in) { + mPolicyType = in.readInt(); + mSsids = (ArraySet<WifiSsid>) in.readArraySet(null); } /** diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java index 060931bdd437..3403ab0db8f3 100644 --- a/core/java/android/app/cloudsearch/SearchResult.java +++ b/core/java/android/app/cloudsearch/SearchResult.java @@ -76,7 +76,7 @@ public final class SearchResult implements Parcelable { public @interface SearchResultExtraInfoKey {} /** This App developer website's domain URL, String value expected. */ public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL"; - /** This App result's ICON URL, String value expected. */ + /** This App icon, android.graphics.drawable.Icon expected. */ public static final String EXTRAINFO_APP_ICON = "APP_ICON"; /** This App developer's name, String value expected. */ public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME"; @@ -114,7 +114,7 @@ public final class SearchResult implements Parcelable { public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE"; /** Web content's URL, String value expected. */ public static final String EXTRAINFO_WEB_URL = "WEB_URL"; - /** Web content's domain icon URL, String value expected. */ + /** Web content's domain icon, android.graphics.drawable.Icon expected. */ public static final String EXTRAINFO_WEB_ICON = "WEB_ICON"; @NonNull diff --git a/core/java/android/app/smartspace/SmartspaceUtils.java b/core/java/android/app/smartspace/SmartspaceUtils.java index f058ffa5a04b..4545f43a8260 100644 --- a/core/java/android/app/smartspace/SmartspaceUtils.java +++ b/core/java/android/app/smartspace/SmartspaceUtils.java @@ -17,6 +17,8 @@ package android.app.smartspace; import android.annotation.Nullable; +import android.app.smartspace.uitemplatedata.SmartspaceText; +import android.text.TextUtils; /** * Utilities for Smartspace data. @@ -28,10 +30,22 @@ public final class SmartspaceUtils { private SmartspaceUtils() { } + /** Returns true if the passed in {@link SmartspaceText} is null or its content is empty. */ + public static boolean isEmpty(@Nullable SmartspaceText text) { + return text == null || TextUtils.isEmpty(text.getText()); + } + + /** Returns true if the passed-in {@link SmartspaceText}s are equal. */ + public static boolean isEqual(@Nullable SmartspaceText text1, @Nullable SmartspaceText text2) { + if (text1 == null && text2 == null) return true; + if (text1 == null || text2 == null) return false; + return text1.equals(text2); + } + /** Returns true if the passed-in {@link CharSequence}s are equal. */ public static boolean isEqual(@Nullable CharSequence cs1, @Nullable CharSequence cs2) { - if ((cs1 == null && cs2 != null) || (cs1 != null && cs2 == null)) return false; if (cs1 == null && cs2 == null) return true; + if (cs1 == null || cs2 == null) return false; return cs1.toString().contentEquals(cs2); } } diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java index c4c4fdef67f9..e996056291bc 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java @@ -23,7 +23,6 @@ import android.app.smartspace.SmartspaceTarget; import android.app.smartspace.SmartspaceUtils; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; import java.util.List; import java.util.Objects; @@ -51,15 +50,15 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT } private SmartspaceCarouselUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, + @Nullable SmartspaceText supplementalAlarmText, @NonNull List<CarouselItem> carouselItems, @Nullable SmartspaceTapAction carouselAction) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, @@ -170,11 +169,11 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT if (mCarouselItems.isEmpty()) { throw new IllegalStateException("Carousel data is empty"); } + return new SmartspaceCarouselUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), - getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), - mCarouselItems, + getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mCarouselItems, mCarouselAction); } } @@ -184,7 +183,7 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT /** Text which is above the image item. */ @Nullable - private final CharSequence mUpperText; + private final SmartspaceText mUpperText; /** Image item. Can be empty. */ @Nullable @@ -192,7 +191,7 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT /** Text which is under the image item. */ @Nullable - private final CharSequence mLowerText; + private final SmartspaceText mLowerText; /** * Tap action for this {@link CarouselItem} instance. {@code mCarouselAction} is used if not @@ -202,14 +201,14 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT private final SmartspaceTapAction mTapAction; CarouselItem(@NonNull Parcel in) { - mUpperText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mUpperText = in.readTypedObject(SmartspaceText.CREATOR); mImage = in.readTypedObject(SmartspaceIcon.CREATOR); - mLowerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mLowerText = in.readTypedObject(SmartspaceText.CREATOR); mTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR); } - private CarouselItem(@Nullable CharSequence upperText, @Nullable SmartspaceIcon image, - @Nullable CharSequence lowerText, @Nullable SmartspaceTapAction tapAction) { + private CarouselItem(@Nullable SmartspaceText upperText, @Nullable SmartspaceIcon image, + @Nullable SmartspaceText lowerText, @Nullable SmartspaceTapAction tapAction) { mUpperText = upperText; mImage = image; mLowerText = lowerText; @@ -217,7 +216,7 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT } @Nullable - public CharSequence getUpperText() { + public SmartspaceText getUpperText() { return mUpperText; } @@ -227,7 +226,7 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT } @Nullable - public CharSequence getLowerText() { + public SmartspaceText getLowerText() { return mLowerText; } @@ -260,9 +259,9 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT @Override public void writeToParcel(@NonNull Parcel out, int flags) { - TextUtils.writeToParcel(mUpperText, out, flags); + out.writeTypedObject(mUpperText, flags); out.writeTypedObject(mImage, flags); - TextUtils.writeToParcel(mLowerText, out, flags); + out.writeTypedObject(mLowerText, flags); out.writeTypedObject(mTapAction, flags); } @@ -300,16 +299,16 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT @SystemApi public static final class Builder { - private CharSequence mUpperText; + private SmartspaceText mUpperText; private SmartspaceIcon mImage; - private CharSequence mLowerText; + private SmartspaceText mLowerText; private SmartspaceTapAction mTapAction; /** * Sets the upper text. */ @NonNull - public Builder setUpperText(@Nullable CharSequence upperText) { + public Builder setUpperText(@Nullable SmartspaceText upperText) { mUpperText = upperText; return this; } @@ -328,7 +327,7 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT * Sets the lower text. */ @NonNull - public Builder setLowerText(@Nullable CharSequence lowerText) { + public Builder setLowerText(@Nullable SmartspaceText lowerText) { mLowerText = lowerText; return this; } @@ -349,7 +348,8 @@ public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiT */ @NonNull public CarouselItem build() { - if (TextUtils.isEmpty(mUpperText) && mImage == null && TextUtils.isEmpty( + if (SmartspaceUtils.isEmpty(mUpperText) && mImage == null + && SmartspaceUtils.isEmpty( mLowerText)) { throw new IllegalStateException("Carousel data is empty"); } diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java index 7e2f74eac4fe..9d4c8e23242c 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java @@ -47,15 +47,15 @@ public final class SmartspaceCombinedCardsUiTemplateData extends SmartspaceDefau } private SmartspaceCombinedCardsUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, + @Nullable SmartspaceText supplementalAlarmText, @NonNull List<SmartspaceDefaultUiTemplateData> combinedCardDataList) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction, @@ -146,7 +146,7 @@ public final class SmartspaceCombinedCardsUiTemplateData extends SmartspaceDefau throw new IllegalStateException("Please assign a value to all @NonNull args."); } return new SmartspaceCombinedCardsUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mCombinedCardDataList); diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java index 742d5c9bdc0e..a7ac9c7ed4bf 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java @@ -24,7 +24,6 @@ import android.app.smartspace.SmartspaceTarget.UiTemplateType; import android.app.smartspace.SmartspaceUtils; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; import java.util.Objects; @@ -50,17 +49,17 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * will be used, which has its own tap action applied to the title area. */ @Nullable - private final CharSequence mTitleText; + private final SmartspaceText mTitleText; @Nullable private final SmartspaceIcon mTitleIcon; /** Subtitle text and icon are shown at the second row. */ @Nullable - private final CharSequence mSubtitleText; + private final SmartspaceText mSubtitleText; @Nullable - private final SmartspaceIcon mSubTitleIcon; + private final SmartspaceIcon mSubtitleIcon; /** * Primary tap action for the entire card, including the blank spaces, except: 1. When title is @@ -75,7 +74,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Mainly used for weather info on non-weather card. */ @Nullable - private final CharSequence mSupplementalSubtitleText; + private final SmartspaceText mSupplementalSubtitleText; @Nullable private final SmartspaceIcon mSupplementalSubtitleIcon; @@ -92,19 +91,19 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * alarm". */ @Nullable - private final CharSequence mSupplementalAlarmText; + private final SmartspaceText mSupplementalAlarmText; SmartspaceDefaultUiTemplateData(@NonNull Parcel in) { mTemplateType = in.readInt(); - mTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mTitleText = in.readTypedObject(SmartspaceText.CREATOR); mTitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR); - mSubtitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mSubTitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR); + mSubtitleText = in.readTypedObject(SmartspaceText.CREATOR); + mSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR); mPrimaryTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR); - mSupplementalSubtitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mSupplementalSubtitleText = in.readTypedObject(SmartspaceText.CREATOR); mSupplementalSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR); mSupplementalSubtitleTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR); - mSupplementalAlarmText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mSupplementalAlarmText = in.readTypedObject(SmartspaceText.CREATOR); } /** @@ -112,20 +111,20 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * SmartspaceDefaultUiTemplateData.Builder. */ SmartspaceDefaultUiTemplateData(@UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, - @Nullable SmartspaceIcon subTitleIcon, + @Nullable SmartspaceText subtitleText, + @Nullable SmartspaceIcon subtitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText) { + @Nullable SmartspaceText supplementalAlarmText) { mTemplateType = templateType; mTitleText = titleText; mTitleIcon = titleIcon; mSubtitleText = subtitleText; - mSubTitleIcon = subTitleIcon; + mSubtitleIcon = subtitleIcon; mPrimaryTapAction = primaryTapAction; mSupplementalSubtitleText = supplementalSubtitleText; mSupplementalSubtitleIcon = supplementalSubtitleIcon; @@ -139,7 +138,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { } @Nullable - public CharSequence getTitleText() { + public SmartspaceText getTitleText() { return mTitleText; } @@ -149,28 +148,28 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { } @Nullable - public CharSequence getSubtitleText() { + public SmartspaceText getSubtitleText() { return mSubtitleText; } @Nullable - public SmartspaceIcon getSubTitleIcon() { - return mSubTitleIcon; + public SmartspaceIcon getSubtitleIcon() { + return mSubtitleIcon; } @Nullable - public CharSequence getSupplementalSubtitleText() { - return mSupplementalSubtitleText; + public SmartspaceTapAction getPrimaryTapAction() { + return mPrimaryTapAction; } @Nullable - public SmartspaceIcon getSupplementalSubtitleIcon() { - return mSupplementalSubtitleIcon; + public SmartspaceText getSupplementalSubtitleText() { + return mSupplementalSubtitleText; } @Nullable - public SmartspaceTapAction getPrimaryTapAction() { - return mPrimaryTapAction; + public SmartspaceIcon getSupplementalSubtitleIcon() { + return mSupplementalSubtitleIcon; } @Nullable @@ -179,7 +178,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { } @Nullable - public CharSequence getSupplementalAlarmText() { + public SmartspaceText getSupplementalAlarmText() { return mSupplementalAlarmText; } @@ -208,15 +207,15 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeInt(mTemplateType); - TextUtils.writeToParcel(mTitleText, out, flags); + out.writeTypedObject(mTitleText, flags); out.writeTypedObject(mTitleIcon, flags); - TextUtils.writeToParcel(mSubtitleText, out, flags); - out.writeTypedObject(mSubTitleIcon, flags); + out.writeTypedObject(mSubtitleText, flags); + out.writeTypedObject(mSubtitleIcon, flags); out.writeTypedObject(mPrimaryTapAction, flags); - TextUtils.writeToParcel(mSupplementalSubtitleText, out, flags); + out.writeTypedObject(mSupplementalSubtitleText, flags); out.writeTypedObject(mSupplementalSubtitleIcon, flags); out.writeTypedObject(mSupplementalSubtitleTapAction, flags); - TextUtils.writeToParcel(mSupplementalAlarmText, out, flags); + out.writeTypedObject(mSupplementalAlarmText, flags); } @Override @@ -228,7 +227,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { that.mTitleText) && Objects.equals(mTitleIcon, that.mTitleIcon) && SmartspaceUtils.isEqual(mSubtitleText, that.mSubtitleText) - && Objects.equals(mSubTitleIcon, that.mSubTitleIcon) + && Objects.equals(mSubtitleIcon, that.mSubtitleIcon) && Objects.equals(mPrimaryTapAction, that.mPrimaryTapAction) && SmartspaceUtils.isEqual(mSupplementalSubtitleText, that.mSupplementalSubtitleText) @@ -240,7 +239,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { @Override public int hashCode() { - return Objects.hash(mTemplateType, mTitleText, mTitleIcon, mSubtitleText, mSubTitleIcon, + return Objects.hash(mTemplateType, mTitleText, mTitleIcon, mSubtitleText, mSubtitleIcon, mPrimaryTapAction, mSupplementalSubtitleText, mSupplementalSubtitleIcon, mSupplementalSubtitleTapAction, mSupplementalAlarmText); } @@ -252,7 +251,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { + ", mTitleText=" + mTitleText + ", mTitleIcon=" + mTitleIcon + ", mSubtitleText=" + mSubtitleText - + ", mSubTitleIcon=" + mSubTitleIcon + + ", mSubTitleIcon=" + mSubtitleIcon + ", mPrimaryTapAction=" + mPrimaryTapAction + ", mSupplementalSubtitleText=" + mSupplementalSubtitleText + ", mSupplementalSubtitleIcon=" + mSupplementalSubtitleIcon @@ -271,15 +270,15 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { public static class Builder { @UiTemplateType private final int mTemplateType; - private CharSequence mTitleText; + private SmartspaceText mTitleText; private SmartspaceIcon mTitleIcon; - private CharSequence mSubtitleText; - private SmartspaceIcon mSubTitleIcon; + private SmartspaceText mSubtitleText; + private SmartspaceIcon mSubtitleIcon; private SmartspaceTapAction mPrimaryTapAction; - private CharSequence mSupplementalSubtitleText; + private SmartspaceText mSupplementalSubtitleText; private SmartspaceIcon mSupplementalSubtitleIcon; private SmartspaceTapAction mSupplementalSubtitleTapAction; - private CharSequence mSupplementalAlarmText; + private SmartspaceText mSupplementalAlarmText; /** * A builder for {@link SmartspaceDefaultUiTemplateData}. @@ -300,7 +299,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { /** Should ONLY be used by the subclasses */ @Nullable @SuppressLint("GetterOnBuilder") - CharSequence getTitleText() { + SmartspaceText getTitleText() { return mTitleText; } @@ -314,15 +313,15 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { /** Should ONLY be used by the subclasses */ @Nullable @SuppressLint("GetterOnBuilder") - CharSequence getSubtitleText() { + SmartspaceText getSubtitleText() { return mSubtitleText; } /** Should ONLY be used by the subclasses */ @Nullable @SuppressLint("GetterOnBuilder") - SmartspaceIcon getSubTitleIcon() { - return mSubTitleIcon; + SmartspaceIcon getSubtitleIcon() { + return mSubtitleIcon; } /** Should ONLY be used by the subclasses */ @@ -335,7 +334,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { /** Should ONLY be used by the subclasses */ @Nullable @SuppressLint("GetterOnBuilder") - CharSequence getSupplementalSubtitleText() { + SmartspaceText getSupplementalSubtitleText() { return mSupplementalSubtitleText; } @@ -356,7 +355,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { /** Should ONLY be used by the subclasses */ @Nullable @SuppressLint("GetterOnBuilder") - CharSequence getSupplementalAlarmText() { + SmartspaceText getSupplementalAlarmText() { return mSupplementalAlarmText; } @@ -364,7 +363,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Sets the card title. */ @NonNull - public Builder setTitleText(@NonNull CharSequence titleText) { + public Builder setTitleText(@NonNull SmartspaceText titleText) { mTitleText = titleText; return this; } @@ -382,7 +381,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Sets the card subtitle. */ @NonNull - public Builder setSubtitleText(@NonNull CharSequence subtitleText) { + public Builder setSubtitleText(@NonNull SmartspaceText subtitleText) { mSubtitleText = subtitleText; return this; } @@ -391,8 +390,8 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Sets the card subtitle icon. */ @NonNull - public Builder setSubTitleIcon(@NonNull SmartspaceIcon subTitleIcon) { - mSubTitleIcon = subTitleIcon; + public Builder setSubtitleIcon(@NonNull SmartspaceIcon subtitleIcon) { + mSubtitleIcon = subtitleIcon; return this; } @@ -409,7 +408,8 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Sets the supplemental subtitle text. */ @NonNull - public Builder setSupplementalSubtitleText(@NonNull CharSequence supplementalSubtitleText) { + public Builder setSupplementalSubtitleText( + @NonNull SmartspaceText supplementalSubtitleText) { mSupplementalSubtitleText = supplementalSubtitleText; return this; } @@ -440,7 +440,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { * Sets the supplemental alarm text. */ @NonNull - public Builder setSupplementalAlarmText(@NonNull CharSequence supplementalAlarmText) { + public Builder setSupplementalAlarmText(@NonNull SmartspaceText supplementalAlarmText) { mSupplementalAlarmText = supplementalAlarmText; return this; } @@ -451,7 +451,7 @@ public class SmartspaceDefaultUiTemplateData implements Parcelable { @NonNull public SmartspaceDefaultUiTemplateData build() { return new SmartspaceDefaultUiTemplateData(mTemplateType, mTitleText, mTitleIcon, - mSubtitleText, mSubTitleIcon, mPrimaryTapAction, mSupplementalSubtitleText, + mSubtitleText, mSubtitleIcon, mPrimaryTapAction, mSupplementalSubtitleText, mSupplementalSubtitleIcon, mSupplementalSubtitleTapAction, mSupplementalAlarmText); } diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java index c76af27e7f16..bcd12eb0f527 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.app.smartspace.SmartspaceTarget; import android.app.smartspace.SmartspaceUtils; import android.os.Parcel; -import android.text.TextUtils; import java.util.Objects; @@ -35,15 +34,15 @@ import java.util.Objects; public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultUiTemplateData { @Nullable - private final CharSequence mHeadToHeadTitle; + private final SmartspaceText mHeadToHeadTitle; @Nullable private final SmartspaceIcon mHeadToHeadFirstCompetitorIcon; @Nullable private final SmartspaceIcon mHeadToHeadSecondCompetitorIcon; @Nullable - private final CharSequence mHeadToHeadFirstCompetitorText; + private final SmartspaceText mHeadToHeadFirstCompetitorText; @Nullable - private final CharSequence mHeadToHeadSecondCompetitorText; + private final SmartspaceText mHeadToHeadSecondCompetitorText; /** Tap action for the head-to-head secondary card. */ @Nullable @@ -51,29 +50,29 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU SmartspaceHeadToHeadUiTemplateData(@NonNull Parcel in) { super(in); - mHeadToHeadTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mHeadToHeadTitle = in.readTypedObject(SmartspaceText.CREATOR); mHeadToHeadFirstCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR); mHeadToHeadSecondCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR); - mHeadToHeadFirstCompetitorText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mHeadToHeadSecondCompetitorText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mHeadToHeadFirstCompetitorText = in.readTypedObject(SmartspaceText.CREATOR); + mHeadToHeadSecondCompetitorText = in.readTypedObject(SmartspaceText.CREATOR); mHeadToHeadAction = in.readTypedObject(SmartspaceTapAction.CREATOR); } private SmartspaceHeadToHeadUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, - @Nullable CharSequence headToHeadTitle, + @Nullable SmartspaceText supplementalAlarmText, + @Nullable SmartspaceText headToHeadTitle, @Nullable SmartspaceIcon headToHeadFirstCompetitorIcon, @Nullable SmartspaceIcon headToHeadSecondCompetitorIcon, - @Nullable CharSequence headToHeadFirstCompetitorText, - @Nullable CharSequence headToHeadSecondCompetitorText, + @Nullable SmartspaceText headToHeadFirstCompetitorText, + @Nullable SmartspaceText headToHeadSecondCompetitorText, @Nullable SmartspaceTapAction headToHeadAction) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction, @@ -87,7 +86,7 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU } @Nullable - public CharSequence getHeadToHeadTitle() { + public SmartspaceText getHeadToHeadTitle() { return mHeadToHeadTitle; } @@ -102,12 +101,12 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU } @Nullable - public CharSequence getHeadToHeadFirstCompetitorText() { + public SmartspaceText getHeadToHeadFirstCompetitorText() { return mHeadToHeadFirstCompetitorText; } @Nullable - public CharSequence getHeadToHeadSecondCompetitorText() { + public SmartspaceText getHeadToHeadSecondCompetitorText() { return mHeadToHeadSecondCompetitorText; } @@ -141,11 +140,11 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU @Override public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); - TextUtils.writeToParcel(mHeadToHeadTitle, out, flags); + out.writeTypedObject(mHeadToHeadTitle, flags); out.writeTypedObject(mHeadToHeadFirstCompetitorIcon, flags); out.writeTypedObject(mHeadToHeadSecondCompetitorIcon, flags); - TextUtils.writeToParcel(mHeadToHeadFirstCompetitorText, out, flags); - TextUtils.writeToParcel(mHeadToHeadSecondCompetitorText, out, flags); + out.writeTypedObject(mHeadToHeadFirstCompetitorText, flags); + out.writeTypedObject(mHeadToHeadSecondCompetitorText, flags); out.writeTypedObject(mHeadToHeadAction, flags); } @@ -195,11 +194,11 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU @SystemApi public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder { - private CharSequence mHeadToHeadTitle; + private SmartspaceText mHeadToHeadTitle; private SmartspaceIcon mHeadToHeadFirstCompetitorIcon; private SmartspaceIcon mHeadToHeadSecondCompetitorIcon; - private CharSequence mHeadToHeadFirstCompetitorText; - private CharSequence mHeadToHeadSecondCompetitorText; + private SmartspaceText mHeadToHeadFirstCompetitorText; + private SmartspaceText mHeadToHeadSecondCompetitorText; private SmartspaceTapAction mHeadToHeadAction; /** @@ -213,7 +212,7 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU * Sets the head-to-head card's title */ @NonNull - public Builder setHeadToHeadTitle(@Nullable CharSequence headToHeadTitle) { + public Builder setHeadToHeadTitle(@Nullable SmartspaceText headToHeadTitle) { mHeadToHeadTitle = headToHeadTitle; return this; } @@ -243,7 +242,7 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU */ @NonNull public Builder setHeadToHeadFirstCompetitorText( - @Nullable CharSequence headToHeadFirstCompetitorText) { + @Nullable SmartspaceText headToHeadFirstCompetitorText) { mHeadToHeadFirstCompetitorText = headToHeadFirstCompetitorText; return this; } @@ -253,7 +252,7 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU */ @NonNull public Builder setHeadToHeadSecondCompetitorText( - @Nullable CharSequence headToHeadSecondCompetitorText) { + @Nullable SmartspaceText headToHeadSecondCompetitorText) { mHeadToHeadSecondCompetitorText = headToHeadSecondCompetitorText; return this; } @@ -273,7 +272,7 @@ public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultU @NonNull public SmartspaceHeadToHeadUiTemplateData build() { return new SmartspaceHeadToHeadUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mHeadToHeadTitle, diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java index 70b30954afa7..1efbaeb8bd3c 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java @@ -42,14 +42,19 @@ public final class SmartspaceIcon implements Parcelable { @Nullable private final CharSequence mContentDescription; + private final boolean mShouldTint; + SmartspaceIcon(@NonNull Parcel in) { mIcon = in.readTypedObject(Icon.CREATOR); mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mShouldTint = in.readBoolean(); } - private SmartspaceIcon(@NonNull Icon icon, @Nullable CharSequence contentDescription) { + private SmartspaceIcon(@NonNull Icon icon, @Nullable CharSequence contentDescription, + boolean shouldTint) { mIcon = icon; mContentDescription = contentDescription; + mShouldTint = shouldTint; } @NonNull @@ -62,6 +67,11 @@ public final class SmartspaceIcon implements Parcelable { return mContentDescription; } + /** Return shouldTint value. The default value is true. */ + public boolean shouldTint() { + return mShouldTint; + } + @NonNull public static final Creator<SmartspaceIcon> CREATOR = new Creator<SmartspaceIcon>() { @Override @@ -80,13 +90,14 @@ public final class SmartspaceIcon implements Parcelable { if (this == o) return true; if (!(o instanceof SmartspaceIcon)) return false; SmartspaceIcon that = (SmartspaceIcon) o; - return mIcon.equals(that.mIcon) && SmartspaceUtils.isEqual(mContentDescription, - that.mContentDescription); + return mIcon.toString().equals(that.mIcon.toString()) && SmartspaceUtils.isEqual( + mContentDescription, + that.mContentDescription) && mShouldTint == that.mShouldTint; } @Override public int hashCode() { - return Objects.hash(mIcon, mContentDescription); + return Objects.hash(mIcon.toString(), mContentDescription, mShouldTint); } @Override @@ -98,13 +109,15 @@ public final class SmartspaceIcon implements Parcelable { public void writeToParcel(@NonNull Parcel out, int flags) { out.writeTypedObject(mIcon, flags); TextUtils.writeToParcel(mContentDescription, out, flags); + out.writeBoolean(mShouldTint); } @Override public String toString() { return "SmartspaceIcon{" - + "mImage=" + mIcon - + ", mContentDescription='" + mContentDescription + '\'' + + "mIcon=" + mIcon + + ", mContentDescription=" + mContentDescription + + ", mShouldTint=" + mShouldTint + '}'; } @@ -118,14 +131,16 @@ public final class SmartspaceIcon implements Parcelable { private Icon mIcon; private CharSequence mContentDescription; + private boolean mShouldTint; /** - * A builder for {@link SmartspaceIcon}. + * A builder for {@link SmartspaceIcon}, which sets shouldTint to true by default. * - * @param icon the icon image of this smartspace icon. + * @param icon the icon image of this {@link SmartspaceIcon} instance. */ public Builder(@NonNull Icon icon) { mIcon = Objects.requireNonNull(icon); + mShouldTint = true; } /** @@ -138,11 +153,20 @@ public final class SmartspaceIcon implements Parcelable { } /** + * Sets should tint icon. + */ + @NonNull + public Builder setShouldTint(boolean shouldTint) { + mShouldTint = shouldTint; + return this; + } + + /** * Builds a new SmartspaceIcon instance. */ @NonNull public SmartspaceIcon build() { - return new SmartspaceIcon(mIcon, mContentDescription); + return new SmartspaceIcon(mIcon, mContentDescription, mShouldTint); } } } diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java index 287cf8e61bc3..2db13d31bba1 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.app.smartspace.SmartspaceTarget; import android.app.smartspace.SmartspaceUtils; import android.os.Parcel; -import android.text.TextUtils; import java.util.Objects; @@ -40,7 +39,7 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe /** Text for the sub-card, which shows below the icon when being set. */ @Nullable - private final CharSequence mSubCardText; + private final SmartspaceText mSubCardText; /** Tap action for the sub-card secondary card. */ @Nullable @@ -49,22 +48,22 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe SmartspaceSubCardUiTemplateData(@NonNull Parcel in) { super(in); mSubCardIcon = in.readTypedObject(SmartspaceIcon.CREATOR); - mSubCardText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mSubCardText = in.readTypedObject(SmartspaceText.CREATOR); mSubCardAction = in.readTypedObject(SmartspaceTapAction.CREATOR); } private SmartspaceSubCardUiTemplateData(int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, + @Nullable SmartspaceText supplementalAlarmText, @NonNull SmartspaceIcon subCardIcon, - @Nullable CharSequence subCardText, + @Nullable SmartspaceText subCardText, @Nullable SmartspaceTapAction subCardAction) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction, @@ -80,7 +79,7 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe } @Nullable - public CharSequence getSubCardText() { + public SmartspaceText getSubCardText() { return mSubCardText; } @@ -115,7 +114,7 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); out.writeTypedObject(mSubCardIcon, flags); - TextUtils.writeToParcel(mSubCardText, out, flags); + out.writeTypedObject(mSubCardText, flags); out.writeTypedObject(mSubCardAction, flags); } @@ -153,7 +152,7 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder { private final SmartspaceIcon mSubCardIcon; - private CharSequence mSubCardText; + private SmartspaceText mSubCardText; private SmartspaceTapAction mSubCardAction; /** @@ -165,11 +164,11 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe } /** - * Sets the card title text. + * Sets the card text. */ @NonNull - public Builder setSubCardAction(@NonNull CharSequence subCardTitleText) { - mSubCardText = subCardTitleText; + public Builder setSubCardText(@NonNull SmartspaceText subCardText) { + mSubCardText = subCardText; return this; } @@ -188,7 +187,7 @@ public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTe @NonNull public SmartspaceSubCardUiTemplateData build() { return new SmartspaceSubCardUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubCardIcon, mSubCardText, diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java index c4799936f8c9..2fe4cf87984a 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java @@ -22,8 +22,6 @@ import android.annotation.SystemApi; import android.app.smartspace.SmartspaceTarget; import android.os.Parcel; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -37,7 +35,7 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT /** Texts are shown next to the image as a vertical list */ @NonNull - private final List<CharSequence> mSubImageTexts; + private final List<SmartspaceText> mSubImageTexts; /** If multiple images are passed in, they will be rendered as GIF. */ @NonNull @@ -49,22 +47,22 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT SmartspaceSubImageUiTemplateData(@NonNull Parcel in) { super(in); - mSubImageTexts = Arrays.asList(in.readCharSequenceArray()); + mSubImageTexts = in.createTypedArrayList(SmartspaceText.CREATOR); mSubImages = in.createTypedArrayList(SmartspaceIcon.CREATOR); mSubImageAction = in.readTypedObject(SmartspaceTapAction.CREATOR); } private SmartspaceSubImageUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, - @NonNull List<CharSequence> subImageTexts, + @Nullable SmartspaceText supplementalAlarmText, + @NonNull List<SmartspaceText> subImageTexts, @NonNull List<SmartspaceIcon> subImages, @Nullable SmartspaceTapAction subImageAction) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, @@ -76,7 +74,7 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT } @NonNull - public List<CharSequence> getSubImageTexts() { + public List<SmartspaceText> getSubImageTexts() { return mSubImageTexts; } @@ -115,7 +113,7 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT @Override public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); - out.writeCharSequenceList(new ArrayList<>(mSubImageTexts)); + out.writeTypedList(mSubImageTexts); out.writeTypedList(mSubImages); out.writeTypedObject(mSubImageAction, flags); } @@ -153,14 +151,14 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT @SystemApi public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder { - private final List<CharSequence> mSubImageTexts; + private final List<SmartspaceText> mSubImageTexts; private final List<SmartspaceIcon> mSubImages; private SmartspaceTapAction mSubImageAction; /** * A builder for {@link SmartspaceSubImageUiTemplateData}. */ - public Builder(@NonNull List<CharSequence> subImageTexts, + public Builder(@NonNull List<SmartspaceText> subImageTexts, @NonNull List<SmartspaceIcon> subImages) { super(SmartspaceTarget.UI_TEMPLATE_SUB_IMAGE); mSubImageTexts = Objects.requireNonNull(subImageTexts); @@ -171,7 +169,7 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT * Sets the card tap action. */ @NonNull - public Builder setCarouselAction(@NonNull SmartspaceTapAction subImageAction) { + public Builder setSubImageAction(@NonNull SmartspaceTapAction subImageAction) { mSubImageAction = subImageAction; return this; } @@ -182,7 +180,7 @@ public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiT @NonNull public SmartspaceSubImageUiTemplateData build() { return new SmartspaceSubImageUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubImageTexts, mSubImages, diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java index b5d9645027d8..9512c7fb130e 100644 --- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java @@ -22,11 +22,10 @@ import android.annotation.SystemApi; import android.app.smartspace.SmartspaceTarget; import android.os.Parcel; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; + /** * Holds all the relevant data needed to render a Smartspace card with the sub-list Ui Template. * @@ -38,7 +37,7 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe @Nullable private final SmartspaceIcon mSubListIcon; @NonNull - private final List<CharSequence> mSubListTexts; + private final List<SmartspaceText> mSubListTexts; /** Tap action for the sub-list secondary card. */ @Nullable @@ -47,22 +46,22 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe SmartspaceSubListUiTemplateData(@NonNull Parcel in) { super(in); mSubListIcon = in.readTypedObject(SmartspaceIcon.CREATOR); - mSubListTexts = Arrays.asList(in.readCharSequenceArray()); + mSubListTexts = in.createTypedArrayList(SmartspaceText.CREATOR); mSubListAction = in.readTypedObject(SmartspaceTapAction.CREATOR); } private SmartspaceSubListUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType, - @Nullable CharSequence titleText, + @Nullable SmartspaceText titleText, @Nullable SmartspaceIcon titleIcon, - @Nullable CharSequence subtitleText, + @Nullable SmartspaceText subtitleText, @Nullable SmartspaceIcon subTitleIcon, @Nullable SmartspaceTapAction primaryTapAction, - @Nullable CharSequence supplementalSubtitleText, + @Nullable SmartspaceText supplementalSubtitleText, @Nullable SmartspaceIcon supplementalSubtitleIcon, @Nullable SmartspaceTapAction supplementalSubtitleTapAction, - @Nullable CharSequence supplementalAlarmText, + @Nullable SmartspaceText supplementalAlarmText, @Nullable SmartspaceIcon subListIcon, - @NonNull List<CharSequence> subListTexts, + @NonNull List<SmartspaceText> subListTexts, @Nullable SmartspaceTapAction subListAction) { super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction, supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction, @@ -78,7 +77,7 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe } @NonNull - public List<CharSequence> getSubListTexts() { + public List<SmartspaceText> getSubListTexts() { return mSubListTexts; } @@ -113,7 +112,7 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); out.writeTypedObject(mSubListIcon, flags); - out.writeCharSequenceList(new ArrayList<>(mSubListTexts)); + out.writeTypedList(mSubListTexts); out.writeTypedObject(mSubListAction, flags); } @@ -151,13 +150,13 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder { private SmartspaceIcon mSubListIcon; - private final List<CharSequence> mSubListTexts; + private final List<SmartspaceText> mSubListTexts; private SmartspaceTapAction mSubListAction; /** * A builder for {@link SmartspaceSubListUiTemplateData}. */ - public Builder(@NonNull List<CharSequence> subListTexts) { + public Builder(@NonNull List<SmartspaceText> subListTexts) { super(SmartspaceTarget.UI_TEMPLATE_SUB_LIST); mSubListTexts = Objects.requireNonNull(subListTexts); } @@ -175,7 +174,7 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe * Sets the card tap action. */ @NonNull - public Builder setCarouselAction(@NonNull SmartspaceTapAction subListAction) { + public Builder setSubListAction(@NonNull SmartspaceTapAction subListAction) { mSubListAction = subListAction; return this; } @@ -186,7 +185,7 @@ public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTe @NonNull public SmartspaceSubListUiTemplateData build() { return new SmartspaceSubListUiTemplateData(getTemplateType(), getTitleText(), - getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(), + getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(), getSupplementalSubtitleText(), getSupplementalSubtitleIcon(), getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubListIcon, mSubListTexts, diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java new file mode 100644 index 000000000000..25d13e6521c6 --- /dev/null +++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java @@ -0,0 +1,143 @@ +/* + * 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 android.app.smartspace.uitemplatedata; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.smartspace.SmartspaceUtils; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.Objects; + +/** + * Holds the information for a Smartspace-card text: the text content and + * the truncate_at information. + * + * @hide + */ +@SystemApi +public final class SmartspaceText implements Parcelable { + + @NonNull + private final CharSequence mText; + + private final TextUtils.TruncateAt mTruncateAtType; + + SmartspaceText(Parcel in) { + mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mTruncateAtType = TextUtils.TruncateAt.valueOf(in.readString()); + } + + private SmartspaceText(@NonNull CharSequence text, TextUtils.TruncateAt truncateAtType) { + mText = text; + mTruncateAtType = truncateAtType; + } + + @NonNull + public CharSequence getText() { + return mText; + } + + @NonNull + public TextUtils.TruncateAt getTruncateAtType() { + return mTruncateAtType; + } + + @NonNull + public static final Creator<SmartspaceText> CREATOR = new Creator<SmartspaceText>() { + @Override + public SmartspaceText createFromParcel(Parcel in) { + return new SmartspaceText(in); + } + + @Override + public SmartspaceText[] newArray(int size) { + return new SmartspaceText[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SmartspaceText)) return false; + SmartspaceText that = (SmartspaceText) o; + return mTruncateAtType == that.mTruncateAtType && SmartspaceUtils.isEqual(mText, + that.mText); + } + + @Override + public int hashCode() { + return Objects.hash(mText, mTruncateAtType); + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + TextUtils.writeToParcel(mText, out, flags); + out.writeString(mTruncateAtType.name()); + } + + /** + * A builder for {@link SmartspaceText} object. + * + * @hide + */ + @SystemApi + public static final class Builder { + private final CharSequence mText; + private TextUtils.TruncateAt mTruncateAtType; + + /** + * A builder for {@link SmartspaceText}, which sets TruncateAtType to AT_END by default. + */ + public Builder(@NonNull CharSequence text) { + mText = Objects.requireNonNull(text); + mTruncateAtType = TextUtils.TruncateAt.END; + } + + /** + * A builder for {@link SmartspaceText}. + */ + public Builder(@NonNull CharSequence text, @NonNull TextUtils.TruncateAt truncateAtType) { + mText = Objects.requireNonNull(text); + mTruncateAtType = Objects.requireNonNull(truncateAtType); + } + + /** + * Sets truncateAtType. + */ + @NonNull + public Builder setTruncateAtType(@NonNull TextUtils.TruncateAt truncateAtType) { + mTruncateAtType = Objects.requireNonNull(truncateAtType); + return this; + } + + /** + * Builds a new SmartspaceText instance. + */ + @NonNull + public SmartspaceText build() { + return new SmartspaceText(mText, mTruncateAtType); + } + } +} diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 157e709a67f0..3f2fa2188d24 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -155,8 +155,8 @@ public final class AttributionSource implements Parcelable { this(AttributionSourceState.CREATOR.createFromParcel(in)); // Since we just unpacked this object as part of it transiting a Binder - // call, this is the perfect time to enforce that its UID can be trusted - enforceCallingUid(); + // call, this is the perfect time to enforce that its UID and PID can be trusted + enforceCallingUidAndPid(); } /** @hide */ @@ -259,13 +259,24 @@ public final class AttributionSource implements Parcelable { } /** + * If you are handling an IPC and you don't trust the caller you need to validate whether the + * attribution source is one for the calling app to prevent the caller to pass you a source from + * another app without including themselves in the attribution chain. + * + * @throws SecurityException if the attribution source cannot be trusted to be from the caller. + */ + private void enforceCallingUidAndPid() { + enforceCallingUid(); + enforceCallingPid(); + } + + /** * If you are handling an IPC and you don't trust the caller you need to validate * whether the attribution source is one for the calling app to prevent the caller * to pass you a source from another app without including themselves in the * attribution chain. * - * @throws SecurityException if the attribution source cannot be trusted to be - * from the caller. + * @throws SecurityException if the attribution source cannot be trusted to be from the caller. */ public void enforceCallingUid() { if (!checkCallingUid()) { @@ -294,6 +305,33 @@ public final class AttributionSource implements Parcelable { return true; } + /** + * Validate that the pid being claimed for the calling app is not spoofed + * + * @throws SecurityException if the attribution source cannot be trusted to be from the caller. + * @hide + */ + @TestApi + public void enforceCallingPid() { + if (!checkCallingPid()) { + throw new SecurityException("Calling pid: " + Binder.getCallingPid() + + " doesn't match source pid: " + mAttributionSourceState.pid); + } + } + + /** + * Validate that the pid being claimed for the calling app is not spoofed + * + * @return if the attribution source cannot be trusted to be from the caller. + */ + private boolean checkCallingPid() { + final int callingPid = Binder.getCallingPid(); + if (mAttributionSourceState.pid != -1 && callingPid != mAttributionSourceState.pid) { + return false; + } + return true; + } + @Override public String toString() { if (Build.IS_DEBUGGABLE) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 07227c5fe0e1..e9466e99c5ca 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3326,7 +3326,8 @@ public abstract class PackageManager { * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined. */ @SdkConstant(SdkConstantType.FEATURE) - public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio"; + public static final String FEATURE_TELEPHONY_RADIO_ACCESS = + "android.hardware.telephony.radio.access"; /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java index ed22de8dd594..85890c1912c5 100644 --- a/core/java/android/hardware/CameraStreamStats.java +++ b/core/java/android/hardware/CameraStreamStats.java @@ -16,6 +16,7 @@ package android.hardware; import android.hardware.camera2.params.DynamicRangeProfiles; +import android.hardware.camera2.CameraMetadata; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -47,6 +48,7 @@ public class CameraStreamStats implements Parcelable { private float[] mHistogramBins; private long[] mHistogramCounts; private int mDynamicRangeProfile; + private int mStreamUseCase; private static final String TAG = "CameraStreamStats"; @@ -63,11 +65,13 @@ public class CameraStreamStats implements Parcelable { mMaxAppBuffers = 0; mHistogramType = HISTOGRAM_TYPE_UNKNOWN; mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; + mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; } public CameraStreamStats(int width, int height, int format, int dataSpace, long usage, long requestCount, long errorCount, - int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile) { + int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile, + int streamUseCase) { mWidth = width; mHeight = height; mFormat = format; @@ -80,6 +84,7 @@ public class CameraStreamStats implements Parcelable { mMaxAppBuffers = maxAppBuffers; mHistogramType = HISTOGRAM_TYPE_UNKNOWN; mDynamicRangeProfile = dynamicRangeProfile; + mStreamUseCase = streamUseCase; } public static final @android.annotation.NonNull Parcelable.Creator<CameraStreamStats> CREATOR = @@ -126,6 +131,7 @@ public class CameraStreamStats implements Parcelable { dest.writeFloatArray(mHistogramBins); dest.writeLongArray(mHistogramCounts); dest.writeInt(mDynamicRangeProfile); + dest.writeInt(mStreamUseCase); } public void readFromParcel(Parcel in) { @@ -143,6 +149,7 @@ public class CameraStreamStats implements Parcelable { mHistogramBins = in.createFloatArray(); mHistogramCounts = in.createLongArray(); mDynamicRangeProfile = in.readInt(); + mStreamUseCase = in.readInt(); } public int getWidth() { @@ -200,4 +207,8 @@ public class CameraStreamStats implements Parcelable { public int getDynamicRangeProfile() { return mDynamicRangeProfile; } + + public int getStreamUseCase() { + return mStreamUseCase; + } } diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index 37cfb4935f0d..0d3aaf575729 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -726,6 +726,89 @@ public final class Sensor { public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker"; /** + * A constant describing a limited axes accelerometer sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + * + */ + public static final int TYPE_ACCELEROMETER_LIMITED_AXES = 38; + + /** + * A constant string describing a limited axes accelerometer sensor. + * + * @see #TYPE_ACCELEROMETER_LIMITED_AXES + * + */ + public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES = + "android.sensor.accelerometer_limited_axes"; + + /** + * A constant describing a limited axes gyroscope sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + * + */ + public static final int TYPE_GYROSCOPE_LIMITED_AXES = 39; + + /** + * A constant string describing a limited axes gyroscope sensor. + * + * @see #TYPE_GYROSCOPE_LIMITED_AXES + * + */ + public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES = + "android.sensor.gyroscope_limited_axes"; + + /** + * A constant describing an uncalibrated limited axes accelerometer sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + * + */ + public static final int TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40; + + /** + * A constant string describing an uncalibrated limited axes accelerometer sensor. + * + * @see #TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED + * + */ + public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = + "android.sensor.accelerometer_limited_axes_uncalibrated"; + + /** + * A constant describing an uncalibrated limited axes gyroscope sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + * + */ + public static final int TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41; + + /** + * A constant string describing an uncalibrated limited axes gyroscope sensor. + * + * @see #TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED + * + */ + public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = + "android.sensor.gyroscope_limited_axes_uncalibrated"; + + /** + * A constant string describing a heading sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + */ + public static final int TYPE_HEADING = 42; + + /** + * A constant string describing a heading sensor. + * + * @see #TYPE_HEADING + * + */ + public static final String STRING_TYPE_HEADING = "android.sensor.heading"; + + /** * A constant describing all sensor types. */ @@ -846,6 +929,11 @@ public final class Sensor { 6, // SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED 1, // SENSOR_TYPE_HINGE_ANGLE 6, // SENSOR_TYPE_HEAD_TRACKER (discontinuity count is excluded) + 6, // SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES + 6, // SENSOR_TYPE_GYROSCOPE_LIMITED_AXES + 9, // SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED + 9, // SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED + 2, // SENSOR_TYPE_HEADING }; /** @@ -1301,6 +1389,21 @@ public final class Sensor { case TYPE_HEAD_TRACKER: mStringType = STRING_TYPE_HEAD_TRACKER; return true; + case TYPE_ACCELEROMETER_LIMITED_AXES: + mStringType = STRING_TYPE_ACCELEROMETER_LIMITED_AXES; + return true; + case TYPE_GYROSCOPE_LIMITED_AXES: + mStringType = STRING_TYPE_GYROSCOPE_LIMITED_AXES; + return true; + case TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED: + mStringType = STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED; + return true; + case TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED: + mStringType = STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED; + return true; + case TYPE_HEADING: + mStringType = STRING_TYPE_HEADING; + return true; default: return false; } diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index c77c8cc635e6..45d4c09921a6 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -676,6 +676,127 @@ public class SensorEvent { * <li> values[5] : Z component of Euler vector representing angular velocity</li> * </ul> * + * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER_LIMITED_AXES + * Sensor.TYPE_ACCELEROMETER_LIMITED_AXES}: + * </h4> Equivalent to TYPE_ACCELEROMETER, but supporting cases where one + * or two axes are not supported. + * + * The last three values represent whether the acceleration value for a + * given axis is supported. A value of 1.0 indicates that the axis is + * supported, while a value of 0 means it isn't supported. The supported + * axes should be determined at build time and these values do not change + * during runtime. + * + * The acceleration values for axes that are not supported are set to 0. + * + * Similar to {@link android.hardware.Sensor#TYPE_ACCELEROMETER}. + * + * <ul> + * <li> values[0]: Acceleration minus Gx on the x-axis (if supported)</li> + * <li> values[1]: Acceleration minus Gy on the y-axis (if supported)</li> + * <li> values[2]: Acceleration minus Gz on the z-axis (if supported)</li> + * <li> values[3]: Acceleration supported for x-axis</li> + * <li> values[4]: Acceleration supported for y-axis</li> + * <li> values[5]: Acceleration supported for z-axis</li> + * </ul> + * + * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE_LIMITED_AXES + * Sensor.TYPE_GYROSCOPE_LIMITED_AXES}: + * </h4> Equivalent to TYPE_GYROSCOPE, but supporting cases where one or two + * axes are not supported. + * + * The last three values represent whether the angular speed value for a + * given axis is supported. A value of 1.0 indicates that the axis is + * supported, while a value of 0 means it isn't supported. The supported + * axes should be determined at build time and these values do not change + * during runtime. + * + * The angular speed values for axes that are not supported are set to 0. + * + * Similar to {@link android.hardware.Sensor#TYPE_GYROSCOPE}. + * + * <ul> + * <li> values[0]: Angular speed around the x-axis (if supported)</li> + * <li> values[1]: Angular speed around the y-axis (if supported)</li> + * <li> values[2]: Angular speed around the z-axis (if supported)</li> + * <li> values[3]: Angular speed supported for x-axis</li> + * <li> values[4]: Angular speed supported for y-axis</li> + * <li> values[5]: Angular speed supported for z-axis</li> + * </ul> + * <p> + * + * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED + * Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED}: + * </h4> Equivalent to TYPE_ACCELEROMETER_UNCALIBRATED, but supporting cases + * where one or two axes are not supported. + * + * The last three values represent whether the acceleration value for a + * given axis is supported. A value of 1.0 indicates that the axis is + * supported, while a value of 0 means it isn't supported. The supported + * axes should be determined at build time and these values do not change + * during runtime. + * + * The acceleration values and bias values for axes that are not supported + * are set to 0. + * + * <ul> + * <li> values[0]: x_uncalib without bias compensation (if supported)</li> + * <li> values[1]: y_uncalib without bias compensation (if supported)</li> + * <li> values[2]: z_uncalib without bias compensation (if supported)</li> + * <li> values[3]: estimated x_bias (if supported)</li> + * <li> values[4]: estimated y_bias (if supported)</li> + * <li> values[5]: estimated z_bias (if supported)</li> + * <li> values[6]: Acceleration supported for x-axis</li> + * <li> values[7]: Acceleration supported for y-axis</li> + * <li> values[8]: Acceleration supported for z-axis</li> + * </ul> + * </p> + * + * <h4> {@link android.hardware.Sensor#TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED + * Sensor.TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED}: + * </h4> Equivalent to TYPE_GYROSCOPE_UNCALIBRATED, but supporting cases + * where one or two axes are not supported. + * + * The last three values represent whether the angular speed value for a + * given axis is supported. A value of 1.0 indicates that the axis is + * supported, while a value of 0 means it isn't supported. The supported + * axes should be determined at build time and these values do not change + * during runtime. + * + * The angular speed values and drift values for axes that are not supported + * are set to 0. + * + * <ul> + * <li> values[0]: Angular speed (w/o drift compensation) around the X axis (if supported)</li> + * <li> values[1]: Angular speed (w/o drift compensation) around the Y axis (if supported)</li> + * <li> values[2]: Angular speed (w/o drift compensation) around the Z axis (if supported)</li> + * <li> values[3]: estimated drift around X axis (if supported)</li> + * <li> values[4]: estimated drift around Y axis (if supported)</li> + * <li> values[5]: estimated drift around Z axis (if supported)</li> + * <li> values[6]: Angular speed supported for x-axis</li> + * <li> values[7]: Angular speed supported for y-axis</li> + * <li> values[8]: Angular speed supported for z-axis</li> + * </ul> + * </p> + * + * <h4>{@link android.hardware.Sensor#TYPE_HEADING Sensor.TYPE_HEADING}:</h4> + * + * A sensor of this type measures the direction in which the device is + * pointing relative to true north in degrees. The value must be between + * 0.0 (inclusive) and 360.0 (exclusive), with 0 indicating north, 90 east, + * 180 south, and 270 west. + * + * Accuracy is defined at 68% confidence. In the case where the underlying + * distribution is assumed Gaussian normal, this would be considered one + * standard deviation. For example, if heading returns 60 degrees, and + * accuracy returns 10 degrees, then there is a 68 percent probability of + * the true heading being between 50 degrees and 70 degrees. + * + * <ul> + * <li> values[0]: Measured heading in degrees.</li> + * <li> values[1]: Heading accuracy in degrees.</li> + * </ul> + * * @see GeomagneticField */ public final float[] values; diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index d2dc314585d6..a29bffe6ea93 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -657,7 +657,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata */ - private <TKey> List<TKey> + <TKey> List<TKey> getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags, boolean includeSynthetic) { @@ -2214,6 +2214,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR ULTRA_HIGH_RESOLUTION_SENSOR}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}</li> + * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE STREAM_USE_CASE}</li> * </ul> * * <p>This key is available on all devices.</p> @@ -2238,6 +2239,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * @see #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR * @see #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING * @see #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT + * @see #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE */ @PublicKey @NonNull @@ -3475,6 +3477,90 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Boolean>("android.scaler.multiResolutionStreamSupported", boolean.class); /** + * <p>The stream use cases supported by this camera device.</p> + * <p>The stream use case indicates the purpose of a particular camera stream from + * the end-user perspective. Some examples of camera use cases are: preview stream for + * live viewfinder shown to the user, still capture for generating high quality photo + * capture, video record for encoding the camera output for the purpose of future playback, + * and video call for live realtime video conferencing.</p> + * <p>With this flag, the camera device can optimize the image processing pipeline + * parameters, such as tuning, sensor mode, and ISP settings, indepedent of + * the properties of the immediate camera output surface. For example, if the output + * surface is a SurfaceTexture, the stream use case flag can be used to indicate whether + * the camera frames eventually go to display, video encoder, + * still image capture, or all of them combined.</p> + * <p>The application sets the use case of a camera stream by calling + * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase }.</p> + * <p>A camera device with + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE } + * capability must support the following stream use cases:</p> + * <ul> + * <li>DEFAULT</li> + * <li>PREVIEW</li> + * <li>STILL_CAPTURE</li> + * <li>VIDEO_RECORD</li> + * <li>PREVIEW_VIDEO_STILL</li> + * <li>VIDEO_CALL</li> + * </ul> + * <p>The guaranteed stream combinations related to stream use case for a camera device with + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE } + * capability is documented in the camera device + * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline}. The + * application is strongly recommended to use one of the guaranteed stream combintations. + * If the application creates a session with a stream combination not in the guaranteed + * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session, + * the camera device may ignore some stream use cases due to hardware constraints + * and implementation details.</p> + * <p>For stream combinations not covered by the stream use case mandatory lists, such as + * reprocessable session, constrained high speed session, or RAW stream combinations, the + * application should leave stream use cases within the session as DEFAULT.</p> + * <p><b>Possible values:</b></p> + * <ul> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}</li> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW PREVIEW}</li> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE STILL_CAPTURE}</li> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD VIDEO_RECORD}</li> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL PREVIEW_VIDEO_STILL}</li> + * <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL VIDEO_CALL}</li> + * </ul> + * + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL + * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + */ + @PublicKey + @NonNull + public static final Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES = + new Key<int[]>("android.scaler.availableStreamUseCases", int[].class); + + /** + * <p>An array of mandatory stream combinations with stream use cases. + * This is an app-readable conversion of the mandatory stream combination + * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables} with + * each stream's use case being set.</p> + * <p>The array of + * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is + * generated according to the documented + * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for a + * camera device with + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE } + * capability. + * The mandatory stream combination array will be {@code null} in case the device doesn't + * have {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE } + * capability.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS = + new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryUseCaseStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class); + + /** * <p>The area of the image sensor which corresponds to active pixels after any geometric * distortion correction has been applied.</p> * <p>This is the rectangle representing the size of the active region of the sensor (i.e. diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 47eb79d07469..1a42eaf541ca 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -404,7 +404,10 @@ public abstract class CameraDevice implements AutoCloseable { * (output format)/(surface type), or if the extension is not * supported, or if any of the output configurations select * a dynamic range different from - * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD} + * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD}, + * or if any of the output configurations sets a stream use + * case different from {@link + * android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT}. * @see CameraExtensionCharacteristics#getSupportedExtensions * @see CameraExtensionCharacteristics#getExtensionSupportedSizes */ @@ -855,6 +858,31 @@ public abstract class CameraDevice implements AutoCloseable { * will cause a capture session initialization failure. * </p> * + * <p>Devices with the STREAM_USE_CASE capability ({@link + * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link + * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional + * stream combinations: + * + * <table> + * <tr><th colspan="10">STREAM_USE_CASE capability additional guaranteed configurations</th></tr> + * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> + * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple preview or in-app image processing</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple video recording or in-app video processing</td> </tr> + * <tr> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple JPEG or YUV still image capture</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code PREVIEW_VIDEO_STILL}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Multi-purpose stream for preview, video and still image capture</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code VIDEO_CALL}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple video call</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>Preview with JPEG or YUV still image capture</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td colspan="3" id="rb"></td> <td>Preview with video recording or in-app video processing</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td colspan="3" id="rb"></td> <td>Preview with in-application image processing</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code VIDEO_CALL}</td> <td colspan="3" id="rb"></td> <td>Preview with video call</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code PREVIEW_VIDEO_STILL}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>Multi-purpose stream with JPEG or YUV still capture</td> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>YUV and JPEG concurrent still image capture (for testing)</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, video record and JPEG or YUV video snapshot</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, in-application image processing, and JPEG or YUV still image capture</td> </tr> + * </table><br> + * </p> + * * <p>Since the capabilities of camera devices vary greatly, a given camera device may support * target combinations with sizes outside of these guarantees, but this can only be tested for * by calling {@link #isSessionConfigurationSupported} or attempting to create a session with diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index 5c636c7fe2f0..aa98f1fdf9bc 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -30,6 +30,7 @@ import android.hardware.camera2.extension.IInitializeSessionCallback; import android.hardware.camera2.extension.IPreviewExtenderImpl; import android.hardware.camera2.extension.LatencyRange; import android.hardware.camera2.extension.SizeList; +import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.os.ConditionVariable; @@ -49,6 +50,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -785,8 +787,8 @@ public final class CameraExtensionCharacteristics { if (latencyRange != null) { return new Range(latencyRange.min, latencyRange.max); } - } - } catch (RemoteException e) { + } + } catch (RemoteException e) { Log.e(TAG, "Failed to query the extension capture latency! Extension service does" + " not respond!"); } finally { @@ -795,4 +797,142 @@ public final class CameraExtensionCharacteristics { return null; } + + /** + * Returns the set of keys supported by a {@link CaptureRequest} submitted in a + * {@link CameraExtensionSession} with a given extension type. + * + * <p>The set returned is not modifiable, so any attempts to modify it will throw + * a {@code UnsupportedOperationException}.</p> + * + * @param extension the extension type + * + * @return non-modifiable set of capture keys supported by camera extension session initialized + * with the given extension type. + * @throws IllegalArgumentException in case of unsupported extension. + */ + @NonNull + public Set<CaptureRequest.Key> getAvailableCaptureRequestKeys(@Extension int extension) { + long clientId = registerClient(mContext); + if (clientId < 0) { + throw new IllegalArgumentException("Unsupported extensions"); + } + + HashSet<CaptureRequest.Key> ret = new HashSet<>(); + + try { + if (!isExtensionSupported(mCameraId, extension, mChars)) { + throw new IllegalArgumentException("Unsupported extension"); + } + Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders = + initializeExtension(extension); + extenders.second.onInit(mCameraId, mChars.getNativeMetadata()); + extenders.second.init(mCameraId, mChars.getNativeMetadata()); + CameraMetadataNative captureRequestMeta = + extenders.second.getAvailableCaptureRequestKeys(); + + if (captureRequestMeta != null) { + int[] requestKeys = captureRequestMeta.get( + CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS); + if (requestKeys == null) { + throw new AssertionError("android.request.availableRequestKeys must be non-null" + + " in the characteristics"); + } + CameraCharacteristics requestChars = new CameraCharacteristics(captureRequestMeta); + + Object crKey = CaptureRequest.Key.class; + Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey; + + ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped, + requestKeys, /*includeSynthetic*/ false)); + } + + // Jpeg quality and orientation must always be supported + if (!ret.contains(CaptureRequest.JPEG_QUALITY)) { + ret.add(CaptureRequest.JPEG_QUALITY); + } + if (!ret.contains(CaptureRequest.JPEG_ORIENTATION)) { + ret.add(CaptureRequest.JPEG_ORIENTATION); + } + extenders.second.onDeInit(); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to query the available capture request keys!"); + } finally { + unregisterClient(clientId); + } + + return Collections.unmodifiableSet(ret); + } + + /** + * Returns the set of keys supported by a {@link CaptureResult} passed as an argument to + * {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}. + * + * <p>The set returned is not modifiable, so any attempts to modify it will throw + * a {@code UnsupportedOperationException}.</p> + * + * <p>In case the set is empty, then the extension is not able to support any capture results + * and the {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable} + * callback will not be fired.</p> + * + * @param extension the extension type + * + * @return non-modifiable set of capture result keys supported by camera extension session + * initialized with the given extension type. + * @throws IllegalArgumentException in case of unsupported extension. + */ + @NonNull + public Set<CaptureResult.Key> getAvailableCaptureResultKeys(@Extension int extension) { + long clientId = registerClient(mContext); + if (clientId < 0) { + throw new IllegalArgumentException("Unsupported extensions"); + } + + HashSet<CaptureResult.Key> ret = new HashSet<>(); + try { + if (!isExtensionSupported(mCameraId, extension, mChars)) { + throw new IllegalArgumentException("Unsupported extension"); + } + + Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders = + initializeExtension(extension); + extenders.second.onInit(mCameraId, mChars.getNativeMetadata()); + extenders.second.init(mCameraId, mChars.getNativeMetadata()); + CameraMetadataNative captureResultMeta = + extenders.second.getAvailableCaptureResultKeys(); + + if (captureResultMeta != null) { + int[] resultKeys = captureResultMeta.get( + CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS); + if (resultKeys == null) { + throw new AssertionError("android.request.availableResultKeys must be non-null " + + "in the characteristics"); + } + CameraCharacteristics resultChars = new CameraCharacteristics(captureResultMeta); + Object crKey = CaptureResult.Key.class; + Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey; + + ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped, + resultKeys, /*includeSynthetic*/ false)); + + // Jpeg quality, orientation and sensor timestamp must always be supported + if (!ret.contains(CaptureResult.JPEG_QUALITY)) { + ret.add(CaptureResult.JPEG_QUALITY); + } + if (!ret.contains(CaptureResult.JPEG_ORIENTATION)) { + ret.add(CaptureResult.JPEG_ORIENTATION); + } + if (!ret.contains(CaptureResult.SENSOR_TIMESTAMP)) { + ret.add(CaptureResult.SENSOR_TIMESTAMP); + } + } + extenders.second.onDeInit(); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to query the available capture result keys!"); + } finally { + unregisterClient(clientId); + } + + return Collections.unmodifiableSet(ret); + } } diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java index 5892f682dd49..ee3441fc16f1 100644 --- a/core/java/android/hardware/camera2/CameraExtensionSession.java +++ b/core/java/android/hardware/camera2/CameraExtensionSession.java @@ -172,6 +172,32 @@ public abstract class CameraExtensionSession implements AutoCloseable { int sequenceId) { // default empty implementation } + + /** + * This method is called when an image capture has fully completed and all the + * result metadata is available. + * + * <p>This callback will only be called in case + * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys} returns a valid + * non-empty list.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param session The session received during + * {@link StateCallback#onConfigured(CameraExtensionSession)} + * @param request The request that was given to the CameraDevice + * @param result The total output metadata from the capture, which only includes the + * capture result keys advertised as supported in + * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys}. + * + * @see #capture + * @see #setRepeatingRequest + * @see CameraExtensionCharacteristics#getAvailableCaptureResultKeys + */ + public void onCaptureResultAvailable(@NonNull CameraExtensionSession session, + @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { + // default empty implementation + } } /** diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 803684da6ddb..95238ee4e6a6 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1210,6 +1210,36 @@ public abstract class CameraMetadata<TKey> { */ public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18; + /** + * <p>The camera device supports selecting a per-stream use case via + * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase } + * so that the device can optimize camera pipeline parameters such as tuning, sensor + * mode, or ISP settings for a specific user scenario. + * Some sample usages of this capability are: + * * Distinguish high quality YUV captures from a regular YUV stream where + * the image quality may not be as good as the JPEG stream, or + * * Use one stream to serve multiple purposes: viewfinder, video recording and + * still capture. This is common with applications that wish to apply edits equally + * to preview, saved images, and saved videos.</p> + * <p>This capability requires the camera device to support the following + * stream use cases: + * * DEFAULT for backward compatibility where the application doesn't set + * a stream use case + * * PREVIEW for live viewfinder and in-app image analysis + * * STILL_CAPTURE for still photo capture + * * VIDEO_RECORD for recording video clips + * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video + * recording, and still capture. + * * VIDEO_CALL for long running video calls</p> + * <p>{@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES } + * lists all of the supported stream use cases.</p> + * <p>Refer to {@link android.hardware.camera2.CameraDevice#createCaptureSession } for the + * mandatory stream combinations involving stream use cases, which can also be queried + * via {@link android.hardware.camera2.params.MandatoryStreamCombination }.</p> + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + */ + public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19; + // // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP // @@ -1336,6 +1366,89 @@ public abstract class CameraMetadata<TKey> { public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // + // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + // + + /** + * <p>Default stream use case.</p> + * <p>This use case is the same as when the application doesn't set any use case for + * the stream. The camera device uses the properties of the output target, such as + * format, dataSpace, or surface class type, to optimize the image processing pipeline.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0; + + /** + * <p>Live stream shown to the user.</p> + * <p>Optimized for performance and usability as a viewfinder, but not necessarily for + * image quality. The output is not meant to be persisted as saved images or video.</p> + * <p>No stall if android.control.<em> are set to FAST; may have stall if android.control.</em> + * are set to HIGH_QUALITY. This use case has the same behavior as the default + * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for + * in-app image analysis.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1; + + /** + * <p>Still photo capture.</p> + * <p>Optimized for high-quality high-resolution capture, and not expected to maintain + * preview-like frame rates.</p> + * <p>The stream may have stalls regardless of whether android.control.* is HIGH_QUALITY. + * This use case has the same behavior as the default JPEG and RAW related formats.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2; + + /** + * <p>Recording video clips.</p> + * <p>Optimized for high-quality video capture, including high-quality image stabilization + * if supported by the device and enabled by the application. As a result, may produce + * output frames with a substantial lag from real time, to allow for highest-quality + * stabilization or other processing. As such, such an output is not suitable for drawing + * to screen directly, and is expected to be persisted to disk or similar for later + * playback or processing. Only streams that set the VIDEO_RECORD use case are guaranteed + * to have video stabilization applied when the video stabilization control is set + * to ON, as opposed to PREVIEW_STABILIZATION.</p> + * <p>This use case has the same behavior as the default MediaRecorder and MediaCodec + * targets.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3; + + /** + * <p>One single stream used for combined purposes of preview, video, and still capture.</p> + * <p>For such multi-purpose streams, the camera device aims to make the best tradeoff + * between the individual use cases. For example, the STILL_CAPTURE use case by itself + * may have stalls for achieving best image quality. But if combined with PREVIEW and + * VIDEO_RECORD, the camera device needs to trade off the additional image processing + * for speed so that preview and video recording aren't slowed down.</p> + * <p>Similarly, VIDEO_RECORD may produce frames with a substantial lag, but + * PREVIEW_VIDEO_STILL must have minimal output delay. This means that to enable video + * stabilization with this use case, the device must support and the app must select the + * PREVIEW_STABILIZATION mode for video stabilization.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4; + + /** + * <p>Long-running video call optimized for both power efficienty and video quality.</p> + * <p>The camera sensor may run in a lower-resolution mode to reduce power consumption + * at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL + * outputs are expected to work in dark conditions, so are usually accompanied with + * variable frame rate settings to allow sufficient exposure time in low light.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5; + + /** + * <p>Vendor defined use cases. These depend on the vendor implementation.</p> + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES + * @hide + */ + public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000; + + // // Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT // diff --git a/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl index 022b084f613b..3c5f5ff63a34 100644 --- a/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl +++ b/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl @@ -17,6 +17,7 @@ package android.hardware.camera2.extension; import android.view.Surface; import android.hardware.camera2.extension.CaptureBundle; +import android.hardware.camera2.extension.IProcessResultImpl; import android.hardware.camera2.extension.Size; /** @hide */ @@ -25,5 +26,5 @@ interface ICaptureProcessorImpl void onOutputSurface(in Surface surface, int imageFormat); void onResolutionUpdate(in Size size); void onImageFormatUpdate(int imageFormat); - void process(in List<CaptureBundle> capturelist); + void process(in List<CaptureBundle> capturelist, in IProcessResultImpl resultCallback); } diff --git a/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl b/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl index 3ebf63793b79..a8a7866e5ca4 100644 --- a/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl +++ b/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl @@ -39,4 +39,6 @@ interface IImageCaptureExtenderImpl int getMaxCaptureStage(); @nullable List<SizeList> getSupportedResolutions(); LatencyRange getEstimatedCaptureLatencyRange(in Size outputSize); + CameraMetadataNative getAvailableCaptureRequestKeys(); + CameraMetadataNative getAvailableCaptureResultKeys(); } diff --git a/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl index f7e4023c5067..ecd098be9d3b 100644 --- a/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl +++ b/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl @@ -17,6 +17,7 @@ package android.hardware.camera2.extension; import android.hardware.camera2.impl.CameraMetadataNative; import android.view.Surface; +import android.hardware.camera2.extension.IProcessResultImpl; import android.hardware.camera2.extension.ParcelImage; import android.hardware.camera2.extension.Size; @@ -26,5 +27,6 @@ interface IPreviewImageProcessorImpl void onOutputSurface(in Surface surface, int imageFormat); void onResolutionUpdate(in Size size); void onImageFormatUpdate(int imageFormat); - void process(in ParcelImage image, in CameraMetadataNative result, int sequenceId); + void process(in ParcelImage image, in CameraMetadataNative result, int sequenceId, + in IProcessResultImpl resultCallback); } diff --git a/core/java/android/net/DhcpResults.aidl b/core/java/android/hardware/camera2/extension/IProcessResultImpl.aidl index f4db3c366d1e..4114edb37a8c 100644 --- a/core/java/android/net/DhcpResults.aidl +++ b/core/java/android/hardware/camera2/extension/IProcessResultImpl.aidl @@ -1,5 +1,5 @@ /** - * Copyright (c) 2012, The Android Open Source Project + * 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. @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package android.hardware.camera2.extension; -package android.net; +import android.hardware.camera2.impl.CameraMetadataNative; -parcelable DhcpResults; +/** @hide */ +interface IProcessResultImpl +{ + void onCaptureCompleted(long shutterTimestamp, in CameraMetadataNative results); +} diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java index 9d2c901ed049..cd392ced2081 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -105,7 +105,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes @RequiresPermission(android.Manifest.permission.CAMERA) public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession( @NonNull CameraDevice cameraDevice, @NonNull Context ctx, - @NonNull ExtensionSessionConfiguration config) + @NonNull ExtensionSessionConfiguration config, int sessionId) throws CameraAccessException, RemoteException { long clientId = CameraExtensionCharacteristics.registerClient(ctx); if (clientId < 0) { @@ -135,6 +135,11 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes throw new IllegalArgumentException("Unsupported dynamic range profile: " + c.getDynamicRangeProfile()); } + if (c.getStreamUseCase() != + CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) { + throw new IllegalArgumentException("Unsupported stream use case: " + + c.getStreamUseCase()); + } } int suitableSurfaceCount = 0; diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java index 2920e670f15b..87553d8c42ab 100644 --- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java @@ -30,9 +30,11 @@ import android.hardware.camera2.utils.SurfaceUtils; import android.os.Handler; import android.os.ConditionVariable; import android.util.Range; +import android.util.Log; import android.view.Surface; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -56,6 +58,7 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl private final CameraCharacteristics mCharacteristics; private final CameraCaptureSessionImpl mSessionImpl; private final ConditionVariable mInitialized = new ConditionVariable(); + private final String TAG = "CameraConstrainedHighSpeedCaptureSessionImpl"; /** * Create a new CameraCaptureSession. @@ -95,10 +98,33 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl StreamConfigurationMap config = mCharacteristics.get(ck); SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config); - // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize - // the preview frame rate, should use maxBatch size for that high speed stream - // configuration. We choose the former for now. - int requestListSize = fpsRange.getUpper() / 30; + // Check the high speed video fps ranges for video size and find the min value from the list + // and assign it to previewFps which will be used to calculate the requestList size. + Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRangesFor( + SurfaceUtils.getSurfaceSize(outputSurfaces.iterator().next())); + Log.v(TAG, "High speed fps ranges: " + Arrays.toString(highSpeedFpsRanges)); + int previewFps = Integer.MAX_VALUE; + for (Range<Integer> range : highSpeedFpsRanges) { + int rangeMin = range.getLower(); + if (previewFps > rangeMin) { + previewFps = rangeMin; + } + } + // Since we only want to support 60fps apart from 30fps, if the min value is not 60, + // then continue to calculate the requestList size using value 30. + if (previewFps != 60 && previewFps != 30) { + Log.w(TAG, "previewFps is neither 60 nor 30."); + previewFps = 30; + } + Log.v(TAG, "previewFps: " + previewFps); + + int requestListSize = fpsRange.getUpper() / previewFps; + // If it's a preview, keep requestList size fixed = 1. + if (fpsRange.getUpper() > fpsRange.getLower()) { + requestListSize = 1; + } + + Log.v(TAG, "Request list size is: " + requestListSize); List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); // Prepare the Request builders: need carry over the request controls. diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 9b19fc4d3ef2..3cb0c93d8409 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -2495,10 +2495,10 @@ public class CameraDeviceImpl extends CameraDevice if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) { mCurrentAdvancedExtensionSession = CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession( - this, mContext, extensionConfiguration); + this, mContext, extensionConfiguration, mNextSessionId++); } else { mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession( - this, mContext, extensionConfiguration); + this, mContext, extensionConfiguration, mNextSessionId++); } } catch (RemoteException e) { throw new CameraAccessException(CameraAccessException.CAMERA_ERROR); diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java index bf4593260a70..d148d87fc9d8 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java @@ -19,6 +19,7 @@ package android.hardware.camera2.impl; import android.annotation.SuppressLint; import android.hardware.camera2.CameraExtensionCharacteristics; import android.hardware.camera2.extension.IPreviewImageProcessorImpl; +import android.hardware.camera2.extension.IProcessResultImpl; import android.hardware.camera2.extension.ParcelImage; import android.hardware.camera2.TotalCaptureResult; import android.media.Image; @@ -114,12 +115,12 @@ public class CameraExtensionForwardProcessor { } } - public void process(ParcelImage image, TotalCaptureResult totalCaptureResult) - throws RemoteException { + public void process(ParcelImage image, TotalCaptureResult totalCaptureResult, + IProcessResultImpl resultCallback) throws RemoteException { if ((mIntermediateSurface != null) && (mIntermediateSurface.isValid()) && !mOutputAbandoned) { mProcessor.process(image, totalCaptureResult.getNativeMetadata(), - totalCaptureResult.getSequenceId()); + totalCaptureResult.getSequenceId(), resultCallback); } } diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java index 425f22c31306..1514a2be5de8 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java @@ -24,6 +24,7 @@ import android.graphics.ImageFormat; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.extension.CaptureBundle; import android.hardware.camera2.extension.ICaptureProcessorImpl; +import android.hardware.camera2.extension.IProcessResultImpl; import android.media.Image; import android.media.Image.Plane; import android.media.ImageReader; @@ -183,11 +184,13 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { int cropLeft, int cropTop, int cropRight, int cropBottom, int rot90); - public void process(List<CaptureBundle> captureBundle) throws RemoteException { + @Override + public void process(List<CaptureBundle> captureBundle, IProcessResultImpl captureCallback) + throws RemoteException { JpegParameters jpegParams = getJpegParameters(captureBundle); try { mJpegParameters.add(jpegParams); - mProcessor.process(captureBundle); + mProcessor.process(captureBundle, captureCallback); } catch (Exception e) { mJpegParameters.remove(jpegParams); throw e; diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java index c8ecfd0bdea9..a50db57e48cd 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java @@ -36,6 +36,7 @@ import android.hardware.camera2.extension.ICaptureProcessorImpl; import android.hardware.camera2.extension.IImageCaptureExtenderImpl; import android.hardware.camera2.extension.IInitializeSessionCallback; import android.hardware.camera2.extension.IPreviewExtenderImpl; +import android.hardware.camera2.extension.IProcessResultImpl; import android.hardware.camera2.extension.IRequestUpdateProcessorImpl; import android.hardware.camera2.extension.ParcelImage; import android.hardware.camera2.TotalCaptureResult; @@ -67,6 +68,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Executor; public final class CameraExtensionSessionImpl extends CameraExtensionSession { @@ -83,6 +85,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { private final StateCallback mCallbacks; private final List<Size> mSupportedPreviewSizes; private final InitializeSessionHandler mInitializeHandler; + private final int mSessionId; + private final Set<CaptureRequest.Key> mSupportedRequestKeys; + private final Set<CaptureResult.Key> mSupportedResultKeys; + private boolean mCaptureResultsSupported; private CameraCaptureSession mCaptureSession = null; private Surface mCameraRepeatingSurface, mClientRepeatingRequestSurface; @@ -121,7 +127,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { public static CameraExtensionSessionImpl createCameraExtensionSession( @NonNull CameraDevice cameraDevice, @NonNull Context ctx, - @NonNull ExtensionSessionConfiguration config) + @NonNull ExtensionSessionConfiguration config, + int sessionId) throws CameraAccessException, RemoteException { long clientId = CameraExtensionCharacteristics.registerClient(ctx); if (clientId < 0) { @@ -151,6 +158,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { throw new IllegalArgumentException("Unsupported dynamic range profile: " + c.getDynamicRangeProfile()); } + if (c.getStreamUseCase() != + CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) { + throw new IllegalArgumentException("Unsupported stream use case: " + + c.getStreamUseCase()); + } } Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders = @@ -197,7 +209,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { repeatingRequestSurface, burstCaptureSurface, config.getStateCallback(), - config.getExecutor()); + config.getExecutor(), + sessionId, + extensionChars.getAvailableCaptureRequestKeys(config.getExtension()), + extensionChars.getAvailableCaptureResultKeys(config.getExtension())); session.initialize(); @@ -212,7 +227,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { @Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface, @NonNull StateCallback callback, - @NonNull Executor executor) { + @NonNull Executor executor, + int sessionId, + @NonNull Set<CaptureRequest.Key> requestKeys, + @Nullable Set<CaptureResult.Key> resultKeys) { mExtensionClientId = extensionClientId; mImageExtender = imageExtender; mPreviewExtender = previewExtender; @@ -227,6 +245,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { mHandler = new Handler(mHandlerThread.getLooper()); mInitialized = false; mInitializeHandler = new InitializeSessionHandler(); + mSessionId = sessionId; + mSupportedRequestKeys = requestKeys; + mSupportedResultKeys = resultKeys; + mCaptureResultsSupported = !resultKeys.isEmpty(); } private void initializeRepeatingRequestPipeline() throws RemoteException { @@ -483,7 +505,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { return captureStageList; } - private static List<CaptureRequest> createBurstRequest(CameraDevice cameraDevice, + private List<CaptureRequest> createBurstRequest(CameraDevice cameraDevice, List<CaptureStageImpl> captureStageList, CaptureRequest clientRequest, Surface target, int captureTemplate, Map<CaptureRequest, Integer> captureMap) { CaptureRequest.Builder requestBuilder; @@ -495,16 +517,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { return null; } - // This will override the extension capture stage jpeg parameters with the user set - // jpeg quality and rotation. This will guarantee that client configured jpeg - // parameters always have highest priority. - Integer jpegRotation = clientRequest.get(CaptureRequest.JPEG_ORIENTATION); - if (jpegRotation != null) { - captureStage.parameters.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation); - } - Byte jpegQuality = clientRequest.get(CaptureRequest.JPEG_QUALITY); - if (jpegQuality != null) { - captureStage.parameters.set(CaptureRequest.JPEG_QUALITY, jpegQuality); + // This will guarantee that client configured + // parameters always have the highest priority. + for (CaptureRequest.Key requestKey : mSupportedRequestKeys){ + Object value = clientRequest.get(requestKey); + if (value != null) { + captureStage.parameters.set(requestKey, value); + } } requestBuilder.addTarget(target); @@ -517,10 +536,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { return ret; } - private static CaptureRequest createRequest(CameraDevice cameraDevice, - List<CaptureStageImpl> captureStageList, - Surface target, - int captureTemplate) throws CameraAccessException { + private CaptureRequest createRequest(CameraDevice cameraDevice, + List<CaptureStageImpl> captureStageList, Surface target, int captureTemplate, + CaptureRequest clientRequest) throws CameraAccessException { CaptureRequest.Builder requestBuilder; requestBuilder = cameraDevice.createCaptureRequest(captureTemplate); if (target != null) { @@ -528,14 +546,35 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } CaptureRequest ret = requestBuilder.build(); + CameraMetadataNative nativeMeta = ret.getNativeMetadata(); for (CaptureStageImpl captureStage : captureStageList) { if (captureStage != null) { - CameraMetadataNative.update(ret.getNativeMetadata(), captureStage.parameters); + CameraMetadataNative.update(nativeMeta, captureStage.parameters); + } + } + + if (clientRequest != null) { + // This will guarantee that client configured + // parameters always have the highest priority. + for (CaptureRequest.Key requestKey : mSupportedRequestKeys) { + Object value = clientRequest.get(requestKey); + if (value != null) { + nativeMeta.set(requestKey, value); + } } } + return ret; } + private CaptureRequest createRequest(CameraDevice cameraDevice, + List<CaptureStageImpl> captureStageList, + Surface target, + int captureTemplate) throws CameraAccessException { + return createRequest(cameraDevice, captureStageList, target, captureTemplate, + /*clientRequest*/ null); + } + @Override public int capture(@NonNull CaptureRequest request, @NonNull Executor executor, @@ -629,12 +668,17 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } private int setRepeatingRequest(CaptureStageImpl captureStage, - CameraCaptureSession.CaptureCallback requestHandler) + CameraCaptureSession.CaptureCallback requestHandler) throws CameraAccessException { + return setRepeatingRequest(captureStage, requestHandler, /*clientRequest*/ null); + } + + private int setRepeatingRequest(CaptureStageImpl captureStage, + CameraCaptureSession.CaptureCallback requestHandler, CaptureRequest clientRequest) throws CameraAccessException { ArrayList<CaptureStageImpl> captureStageList = new ArrayList<>(); captureStageList.add(captureStage); - CaptureRequest repeatingRequest = createRequest(mCameraDevice, - captureStageList, mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW); + CaptureRequest repeatingRequest = createRequest(mCameraDevice, captureStageList, + mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW, clientRequest); return mCaptureSession.setSingleRepeatingRequest(repeatingRequest, new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler); } @@ -843,6 +887,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { private ImageCallback mImageCallback = null; private boolean mCaptureFailed = false; + private CaptureResultHandler mCaptureResultHandler = null; public BurstRequestHandler(@NonNull CaptureRequest request, @NonNull Executor executor, @NonNull ExtensionCaptureCallback callbacks, @@ -963,20 +1008,18 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP); if (timestamp != null) { + if (mCaptureResultsSupported && (mCaptureResultHandler == null)) { + mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor, + mCallbacks, result.getSessionId()); + } if (mImageProcessor != null) { if (mCapturePendingMap.indexOfKey(timestamp) >= 0) { Image img = mCapturePendingMap.get(timestamp).first; - mCaptureStageMap.put(stageId, - new Pair<>(img, - result)); + mCaptureStageMap.put(stageId, new Pair<>(img, result)); checkAndFireBurstProcessing(); } else { - mCapturePendingMap.put(timestamp, - new Pair<>(null, - stageId)); - mCaptureStageMap.put(stageId, - new Pair<>(null, - result)); + mCapturePendingMap.put(timestamp, new Pair<>(null, stageId)); + mCaptureStageMap.put(stageId, new Pair<>(null, result)); } } else { mCaptureRequestMap.clear(); @@ -986,6 +1029,18 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { () -> mCallbacks .onCaptureProcessStarted(CameraExtensionSessionImpl.this, mClientRequest)); + + if (mCaptureResultHandler != null) { + CameraMetadataNative captureResults = new CameraMetadataNative(); + for (CaptureResult.Key key : mSupportedResultKeys) { + Object value = result.get(key); + if (value != null) { + captureResults.set(key, value); + } + } + mCaptureResultHandler.onCaptureCompleted(timestamp, + captureResults); + } } finally { Binder.restoreCallingIdentity(ident); } @@ -1013,7 +1068,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap, jpegOrientation, jpegQuality); try { - mImageProcessor.process(captureList); + mImageProcessor.process(captureList, mCaptureResultHandler); } catch (RemoteException e) { Log.e(TAG, "Failed to process multi-frame request! Extension service " + "does not respond!"); @@ -1228,6 +1283,43 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } } + private class CaptureResultHandler extends IProcessResultImpl.Stub { + private final Executor mExecutor; + private final ExtensionCaptureCallback mCallbacks; + private final CaptureRequest mClientRequest; + private final int mRequestId; + + public CaptureResultHandler(@NonNull CaptureRequest clientRequest, + @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener, + int requestId) { + mClientRequest = clientRequest; + mExecutor = executor; + mCallbacks = listener; + mRequestId = requestId; + } + + @Override + public void onCaptureCompleted(long shutterTimestamp, CameraMetadataNative result) { + if (result == null) { + Log.e(TAG,"Invalid capture result!"); + return; + } + + result.set(CaptureResult.SENSOR_TIMESTAMP, shutterTimestamp); + TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result, + mClientRequest, mRequestId, shutterTimestamp, new ArrayList<CaptureResult>(), + mSessionId, new PhysicalCaptureResultInfo[0]); + final long ident = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallbacks.onCaptureResultAvailable(CameraExtensionSessionImpl.this, + mClientRequest, totalResult)); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + // This handler can operate in two modes: // 1) Using valid client callbacks, which means camera buffers will be propagated the // registered output surfaces and clients will be notified accordingly. @@ -1242,6 +1334,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { private OnImageAvailableListener mImageCallback = null; private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap = new LongSparseArray<>(); + private CaptureResultHandler mCaptureResultHandler = null; private boolean mRequestUpdatedNeeded = false; @@ -1375,6 +1468,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { synchronized (mInterfaceLock) { final Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP); if (timestamp != null) { + if (mCaptureResultsSupported && mClientNotificationsEnabled && + (mCaptureResultHandler == null)) { + mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor, + mCallbacks, result.getSessionId()); + } if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) { CaptureStageImpl captureStage = null; @@ -1387,7 +1485,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } if (captureStage != null) { try { - setRepeatingRequest(captureStage, this); + setRepeatingRequest(captureStage, this, request); mRequestUpdatedNeeded = true; } catch (IllegalStateException e) { // This is possible in case the camera device closes and the @@ -1406,7 +1504,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { ParcelImage parcelImage = initializeParcelImage( mPendingResultMap.get(timestamp).first); try { - mPreviewImageProcessor.process(parcelImage, result); + mPreviewImageProcessor.process(parcelImage, result, + mCaptureResultHandler); } catch (RemoteException e) { processStatus = false; Log.e(TAG, "Extension service does not respond during " + @@ -1444,6 +1543,19 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { .onCaptureProcessStarted( CameraExtensionSessionImpl.this, mClientRequest)); + if ((mCaptureResultHandler != null) && (mPreviewProcessorType != + IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR)) { + CameraMetadataNative captureResults = + new CameraMetadataNative(); + for (CaptureResult.Key key : mSupportedResultKeys) { + Object value = result.get(key); + if (value != null) { + captureResults.set(key, value); + } + } + mCaptureResultHandler.onCaptureCompleted(timestamp, + captureResults); + } } else { mExecutor.execute( () -> mCallbacks @@ -1587,7 +1699,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { ParcelImage parcelImage = initializeParcelImage(img); try { mPreviewImageProcessor.process(parcelImage, - mPendingResultMap.get(timestamp).second); + mPendingResultMap.get(timestamp).second, mCaptureResultHandler); } catch (RemoteException e) { processStatus = false; Log.e(TAG, "Extension service does not respond during " + diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 0f8bdf64e132..9b67633fe72b 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -333,6 +333,7 @@ public class CameraMetadataNative implements Parcelable { private static final int MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION = 1; private static final int MANDATORY_STREAM_CONFIGURATIONS_CONCURRENT = 2; private static final int MANDATORY_STREAM_CONFIGURATIONS_10BIT = 3; + private static final int MANDATORY_STREAM_CONFIGURATIONS_USE_CASE = 4; private static String translateLocationProviderToProcess(final String provider) { if (provider == null) { @@ -700,6 +701,16 @@ public class CameraMetadataNative implements Parcelable { }); sGetCommandMap.put( + CameraCharacteristics.SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getMandatoryUseCaseStreamCombinations(); + } + }); + + sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() { @Override @SuppressWarnings("unchecked") @@ -1413,6 +1424,9 @@ public class CameraMetadataNative implements Parcelable { case MANDATORY_STREAM_CONFIGURATIONS_10BIT: combs = build.getAvailableMandatory10BitStreamCombinations(); break; + case MANDATORY_STREAM_CONFIGURATIONS_USE_CASE: + combs = build.getAvailableMandatoryStreamUseCaseCombinations(); + break; default: combs = build.getAvailableMandatoryStreamCombinations(); } @@ -1446,6 +1460,10 @@ public class CameraMetadataNative implements Parcelable { return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_DEFAULT); } + private MandatoryStreamCombination[] getMandatoryUseCaseStreamCombinations() { + return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_USE_CASE); + } + private StreamConfigurationMap getStreamConfigurationMap() { StreamConfiguration[] configurations = getBase( CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java index 32c15da4a909..0d93c985b793 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -26,6 +26,9 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.params.OutputConfiguration; +import android.hardware.camera2.params.OutputConfiguration.StreamUseCase; +import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.HashCodeHelpers; import android.media.CamcorderProfile; import android.util.Log; @@ -63,6 +66,7 @@ public final class MandatoryStreamCombination { private final boolean mIsUltraHighResolution; private final boolean mIsMaximumSize; private final boolean mIs10BitCapable; + private final int mStreamUseCase; /** * Create a new {@link MandatoryStreamInformation}. @@ -141,6 +145,30 @@ public final class MandatoryStreamCombination { public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format, boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution, boolean is10BitCapable) { + this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution, + is10BitCapable, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT); + } + + /** + * Create a new {@link MandatoryStreamInformation}. + * + * @param availableSizes List of possible stream sizes. + * @param format Image format. + * @param isMaximumSize Whether this is a maximum size stream. + * @param isInput Flag indicating whether this stream is input. + * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution + * stream. + * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit + * @param streamUseCase The stream use case. + * + * @throws IllegalArgumentException + * if sizes is empty or if the format was not user-defined in + * ImageFormat/PixelFormat. + * @hide + */ + public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format, + boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution, + boolean is10BitCapable, @StreamUseCase int streamUseCase) { if (availableSizes.isEmpty()) { throw new IllegalArgumentException("No available sizes"); } @@ -150,6 +178,7 @@ public final class MandatoryStreamCombination { mIsInput = isInput; mIsUltraHighResolution = isUltraHighResolution; mIs10BitCapable = is10BitCapable; + mStreamUseCase = streamUseCase; } /** @@ -272,6 +301,20 @@ public final class MandatoryStreamCombination { } /** + * Retrieve the mandatory stream use case. + * + * <p>If this {@link MandatoryStreamInformation} is part of a mandatory stream + * combination for stream use cases, the return value will be a non-DEFAULT value. + * For {@link MandatoryStreamInformation} belonging to other mandatory stream + * combinations, the return value will be DEFAULT. </p> + * + * @return the integer stream use case. + */ + public @StreamUseCase int getStreamUseCase() { + return mStreamUseCase; + } + + /** * Check if this {@link MandatoryStreamInformation} is equal to another * {@link MandatoryStreamInformation}. * @@ -292,6 +335,7 @@ public final class MandatoryStreamCombination { final MandatoryStreamInformation other = (MandatoryStreamInformation) obj; if ((mFormat != other.mFormat) || (mIsInput != other.mIsInput) || (mIsUltraHighResolution != other.mIsUltraHighResolution) || + (mStreamUseCase != other.mStreamUseCase) || (mAvailableSizes.size() != other.mAvailableSizes.size())) { return false; } @@ -308,7 +352,8 @@ public final class MandatoryStreamCombination { @Override public int hashCode() { return HashCodeHelpers.hashCode(mFormat, Boolean.hashCode(mIsInput), - Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode()); + Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode(), + mStreamUseCase); } } @@ -316,6 +361,21 @@ public final class MandatoryStreamCombination { private final boolean mIsReprocessable; private final ArrayList<MandatoryStreamInformation> mStreamsInformation = new ArrayList<MandatoryStreamInformation>(); + + /** + * Short hand for stream use cases + */ + private static final int STREAM_USE_CASE_PREVIEW = + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW; + private static final int STREAM_USE_CASE_STILL_CAPTURE = + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE; + private static final int STREAM_USE_CASE_RECORD = + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD; + private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL = + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL; + private static final int STREAM_USE_CASE_VIDEO_CALL = + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL; + /** * Create a new {@link MandatoryStreamCombination}. * @@ -411,15 +471,15 @@ public final class MandatoryStreamCombination { private static final class StreamTemplate { public int mFormat; public SizeThreshold mSizeThreshold; - public boolean mIsInput; + public int mStreamUseCase; public StreamTemplate(int format, SizeThreshold sizeThreshold) { - this(format, sizeThreshold, /*isInput*/false); + this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT); } public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold, - boolean isInput) { + @StreamUseCase int streamUseCase) { mFormat = format; mSizeThreshold = sizeThreshold; - mIsInput = isInput; + mStreamUseCase = streamUseCase; } } @@ -1034,6 +1094,174 @@ public final class MandatoryStreamCombination { "High-resolution recording with video snapshot"), }; + private static StreamCombinationTemplate sStreamUseCaseCombinations[] = { + // Single stream combinations + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW) }, + "Simple preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW) }, + "Simple in-application image processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD) }, + "Simple video recording"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD) }, + "Simple in-application video processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE) }, + "Simple JPEG still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE) }, + "Simple YUV still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL) }, + "Multi-purpose stream for preview, video and still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL) }, + "Multi-purpose YUV stream for preview, video and still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p, + STREAM_USE_CASE_VIDEO_CALL) }, + "Simple video call"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p, + STREAM_USE_CASE_VIDEO_CALL) }, + "Simple YUV video call"), + + // 2-stream combinations + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview with JPEG still image capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview with YUV still image capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD)}, + "Preview with video recording"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD)}, + "Preview with in-application video processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW)}, + "Preview with in-application image processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p, + STREAM_USE_CASE_VIDEO_CALL)}, + "Preview with video call"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p, + STREAM_USE_CASE_VIDEO_CALL)}, + "Preview with YUV video call"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Multi-purpose stream with JPEG still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Multi-purpose stream with YUV still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Multi-purpose YUV stream with JPEG still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p, + STREAM_USE_CASE_PREVIEW_VIDEO_STILL), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Multi-purpose YUV stream with YUV still capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW, + STREAM_USE_CASE_STILL_CAPTURE), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "YUV and JPEG concurrent still image capture (for testing)"), + + // 3-stream combinations + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, video record and JPEG video snapshot"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, video record and YUV video snapshot"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, in-application video processing and JPEG video snapshot"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_RECORD), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, in-application video processing and YUV video snapshot"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, in-application image processing, and JPEG still image capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW, + STREAM_USE_CASE_PREVIEW), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM, + STREAM_USE_CASE_STILL_CAPTURE)}, + "Preview, in-application image processing, and YUV still image capture"), + }; + /** * Helper builder class to generate a list of available mandatory stream combinations. * @hide @@ -1153,6 +1381,76 @@ public final class MandatoryStreamCombination { } /** + * Retrieve a list of all available mandatory stream combinations with stream use cases. + * when the camera device has {@link + * CameraMetdata.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} capability. + * + * @return a non-modifiable list of supported mandatory stream combinations with stream + * use cases. Null in case the device doesn't have {@link + * CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} + * capability. + */ + public @NonNull List<MandatoryStreamCombination> + getAvailableMandatoryStreamUseCaseCombinations() { + if (!isCapabilitySupported( + CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) { + return null; + } + + HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes = + enumerateAvailableSizes(); + if (availableSizes == null) { + Log.e(TAG, "Available size enumeration failed!"); + return null; + } + + ArrayList<MandatoryStreamCombination> availableStreamCombinations = new ArrayList<>(); + availableStreamCombinations.ensureCapacity(sStreamUseCaseCombinations.length); + for (StreamCombinationTemplate combTemplate : sStreamUseCaseCombinations) { + ArrayList<MandatoryStreamInformation> streamsInfo = + new ArrayList<MandatoryStreamInformation>(); + streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length); + + for (StreamTemplate template : combTemplate.mStreamTemplates) { + List<Size> sizes = null; + Pair<SizeThreshold, Integer> pair; + pair = new Pair<SizeThreshold, Integer>(template.mSizeThreshold, + new Integer(template.mFormat)); + sizes = availableSizes.get(pair); + + MandatoryStreamInformation streamInfo; + boolean isMaximumSize = + (template.mSizeThreshold == SizeThreshold.MAXIMUM); + try { + streamInfo = new MandatoryStreamInformation(sizes, template.mFormat, + isMaximumSize, /*isInput*/false, /*isUltraHighResolution*/false, + /*is10BitCapable*/ false, template.mStreamUseCase); + } catch (IllegalArgumentException e) { + Log.e(TAG, "No available sizes found for format: " + template.mFormat + + " size threshold: " + template.mSizeThreshold + " combination: " + + combTemplate.mDescription); + return null; + } + streamsInfo.add(streamInfo); + } + + MandatoryStreamCombination streamCombination; + try { + streamCombination = new MandatoryStreamCombination(streamsInfo, + combTemplate.mDescription, /*isReprocessable*/ false); + } catch (IllegalArgumentException e) { + Log.e(TAG, "No stream information for mandatory combination: " + + combTemplate.mDescription); + return null; + } + + availableStreamCombinations.add(streamCombination); + } + + return Collections.unmodifiableList(availableStreamCombinations); + } + + /** * Retrieve a list of all available mandatory concurrent stream combinations. * This method should only be called for devices which are listed in combinations returned * by CameraManager.getConcurrentCameraIds. @@ -1632,6 +1930,8 @@ public final class MandatoryStreamCombination { Size recordingMaxSize = new Size(0, 0); Size previewMaxSize = new Size(0, 0); Size vgaSize = new Size(640, 480); + Size s720pSize = new Size(1280, 720); + Size s1440pSize = new Size(1920, 1440); // For external camera, or hidden physical camera, CamcorderProfile may not be // available, so get maximum recording size using stream configuration map. if (isExternalCamera() || mIsHiddenPhysicalCamera) { @@ -1682,6 +1982,12 @@ public final class MandatoryStreamCombination { pair = new Pair<SizeThreshold, Integer>(SizeThreshold.MAXIMUM, intFormat); availableSizes.put(pair, Arrays.asList(sizes)); + + pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s720p, intFormat); + availableSizes.put(pair, getSizesWithinBound(sizes, s720pSize)); + + pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s1440p, intFormat); + availableSizes.put(pair, getSizesWithinBound(sizes, s1440pSize)); } return availableSizes; diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index f2b881ba7758..d8295c962154 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -159,6 +159,17 @@ public final class OutputConfiguration implements Parcelable { CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION}) public @interface SensorPixelMode {}; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"STREAM_USE_CASE_"}, value = + {CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW, + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE, + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD, + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL, + CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL}) + public @interface StreamUseCase {}; + /** * Create a new {@link OutputConfiguration} instance with a {@link Surface}. * @@ -355,6 +366,7 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList<Integer>(); mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; + mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; } /** @@ -453,6 +465,7 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList<Integer>(); mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; + mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; } /** @@ -730,6 +743,73 @@ public final class OutputConfiguration implements Parcelable { } /** + * Set stream use case for this OutputConfiguration + * + * <p>Stream use case is used to describe the purpose of the stream, whether it's for live + * preview, still image capture, video recording, or their combinations. This flag is useful + * for scenarios where the immediate consumer target isn't sufficient to indicate the stream's + * usage.</p> + * + * <p>The main difference beteween stream use case and capture intent is that the former + * enables the camera device to optimize camera hardware and software pipelines based on user + * scenarios for each stream, whereas the latter is mainly a hint to camera to decide + * optimal 3A strategy that's applicable to the whole session. The camera device carries out + * configurations such as selecting tuning parameters, choosing camera sensor mode, and + * constructing image processing pipeline based on the streams's use cases. Capture intents are + * then used to fine tune 3A behaviors such as adjusting AE/AF convergence speed, and capture + * intents may change during the lifetime of a session. For example, for a session with a + * PREVIEW_VIDEO_STILL use case stream and a STILL_CAPTURE use case stream, the capture intents + * may be PREVIEW with fast 3A convergence speed and flash metering with automatic control for + * live preview, STILL_CAPTURE with best 3A parameters for still photo capture, or VIDEO_RECORD + * with slower 3A convergence speed for better video playback experience.</p> + * + * <p>The supported stream use cases supported by a camera device can be queried by + * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}.</p> + * + * <p>The mandatory stream combinations involving stream use cases can be found at {@link + * android.hardware.camera2.CameraDevice#createCaptureSession}, as well as queried via + * {@link android.hardware.camera2.params.MandatoryStreamCombination}. The application is + * strongly recommended to select one of the guaranteed stream combinations where all streams' + * use cases are set to non-DEFAULT values. If the application chooses a stream combination + * not in the mandatory list, the camera device may ignore some use case flags due to + * hardware constraints or implementation details.</p> + * + * <p>This function must be called before {@link CameraDevice#createCaptureSession} or {@link + * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after + * {@link CameraDevice#createCaptureSession} or + * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect to the camera + * session.</p> + * + * @param streamUseCase The stream use case to be set. + * + * @throws IllegalArgumentException If the streamUseCase isn't within the range of valid + * values. + */ + public void setStreamUseCase(@StreamUseCase int streamUseCase) { + // Verify that the value is in range + int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL; + if (streamUseCase > maxUseCaseValue && + streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) { + throw new IllegalArgumentException("Not a valid stream use case value " + + streamUseCase); + } + + mStreamUseCase = streamUseCase; + } + + /** + * Get the current stream use case + * + * <p>If no {@link #setStreamUseCase} is called first, this function returns + * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}.</p> + * + * @return the currently set stream use case + */ + public int getStreamUseCase() { + return mStreamUseCase; + } + + /** * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration} * instance. * @@ -756,6 +836,7 @@ public final class OutputConfiguration implements Parcelable { this.mIsMultiResolution = other.mIsMultiResolution; this.mSensorPixelModesUsed = other.mSensorPixelModesUsed; this.mDynamicRangeProfile = other.mDynamicRangeProfile; + this.mStreamUseCase = other.mStreamUseCase; } /** @@ -774,6 +855,8 @@ public final class OutputConfiguration implements Parcelable { String physicalCameraId = source.readString(); boolean isMultiResolutionOutput = source.readInt() == 1; int[] sensorPixelModesUsed = source.createIntArray(); + int streamUseCase = source.readInt(); + checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); int dynamicRangeProfile = source.readInt(); DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile); @@ -801,6 +884,7 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = isMultiResolutionOutput; mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed); mDynamicRangeProfile = dynamicRangeProfile; + mStreamUseCase = streamUseCase; } /** @@ -917,6 +1001,7 @@ public final class OutputConfiguration implements Parcelable { // writeList doesn't seem to work well with Integer list. dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed)); dest.writeInt(mDynamicRangeProfile); + dest.writeInt(mStreamUseCase); } /** @@ -947,7 +1032,8 @@ public final class OutputConfiguration implements Parcelable { mConfiguredDataspace != other.mConfiguredDataspace || mConfiguredGenerationId != other.mConfiguredGenerationId || !Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) || - mIsMultiResolution != other.mIsMultiResolution) + mIsMultiResolution != other.mIsMultiResolution || + mStreamUseCase != other.mStreamUseCase) return false; if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) { return false; @@ -985,7 +1071,7 @@ public final class OutputConfiguration implements Parcelable { mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0, mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), - mDynamicRangeProfile); + mDynamicRangeProfile, mStreamUseCase); } return HashCodeHelpers.hashCode( @@ -994,7 +1080,7 @@ public final class OutputConfiguration implements Parcelable { mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0, mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), - mDynamicRangeProfile); + mDynamicRangeProfile, mStreamUseCase); } private static final String TAG = "OutputConfiguration"; @@ -1028,4 +1114,6 @@ public final class OutputConfiguration implements Parcelable { private ArrayList<Integer> mSensorPixelModesUsed; // Dynamic range profile private int mDynamicRangeProfile; + // Stream use case + private int mStreamUseCase; } diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java index dbe7a418b0fc..c3113799ad45 100644 --- a/core/java/android/hardware/lights/Light.java +++ b/core/java/android/hardware/lights/Light.java @@ -38,6 +38,12 @@ public final class Light implements Parcelable { /** Type for lights that indicate microphone usage */ public static final int LIGHT_TYPE_MICROPHONE = 8; + /** Type for lights that indicate camera usage + * + * @hide + */ + public static final int LIGHT_TYPE_CAMERA = 9; + // These enum values start from 10001 to avoid collision with expanding of HAL light types. /** * Type for lights that indicate a monochrome color LED light. diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 223b8ccf44c8..fc2fbc39dbeb 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -346,7 +346,7 @@ public class InputMethodService extends AbstractInputMethodService { */ @AnyThread public static boolean canImeRenderGesturalNavButtons() { - return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false); + return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true); } /** diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java index 83fc7276eabc..c3bb381bb740 100644 --- a/core/java/android/inputmethodservice/NavigationBarController.java +++ b/core/java/android/inputmethodservice/NavigationBarController.java @@ -219,7 +219,7 @@ final class NavigationBarController { // TODO(b/213337792): Set NAVIGATION_HINT_IME_SHOWN only when necessary. final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT | (mShouldShowImeSwitcherWhenImeIsShown - ? StatusBarManager.NAVIGATION_HINT_IME_SHOWN + ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0); navigationBarView.setNavigationIconHints(hints); } @@ -470,7 +470,7 @@ final class NavigationBarController { } final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT | (shouldShowImeSwitcherWhenImeIsShown - ? StatusBarManager.NAVIGATION_HINT_IME_SHOWN : 0); + ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0); navigationBarView.setNavigationIconHints(hints); } diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java index 42847784dd2b..a2d71054c65d 100644 --- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java +++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java @@ -270,7 +270,7 @@ public final class NavigationBarView extends FrameLayout { // Update IME button visibility, a11y and rotate button always overrides the appearance final boolean imeSwitcherVisible = - (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0; + (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0; getImeSwitchButton().setVisibility(imeSwitcherVisible ? View.VISIBLE : View.INVISIBLE); getBackButton().setVisibility(View.VISIBLE); diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java deleted file mode 100644 index 82ba156b08d0..000000000000 --- a/core/java/android/net/DhcpResults.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; - -import com.android.net.module.util.InetAddressUtils; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * A simple object for retrieving the results of a DHCP request. - * Optimized (attempted) for that jni interface - * TODO: remove this class and replace with other existing constructs - * @hide - */ -public final class DhcpResults implements Parcelable { - private static final String TAG = "DhcpResults"; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public LinkAddress ipAddress; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public InetAddress gateway; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public final ArrayList<InetAddress> dnsServers = new ArrayList<>(); - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String domains; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Inet4Address serverAddress; - - /** Vendor specific information (from RFC 2132). */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String vendorInfo; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int leaseDuration; - - /** Link MTU option. 0 means unset. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int mtu; - - public String serverHostName; - - @Nullable - public String captivePortalApiUrl; - - public DhcpResults() { - super(); - } - - /** - * Create a {@link StaticIpConfiguration} based on the DhcpResults. - */ - public StaticIpConfiguration toStaticIpConfiguration() { - return new StaticIpConfiguration.Builder() - .setIpAddress(ipAddress) - .setGateway(gateway) - .setDnsServers(dnsServers) - .setDomains(domains) - .build(); - } - - public DhcpResults(StaticIpConfiguration source) { - if (source != null) { - ipAddress = source.getIpAddress(); - gateway = source.getGateway(); - dnsServers.addAll(source.getDnsServers()); - domains = source.getDomains(); - } - } - - /** copy constructor */ - public DhcpResults(DhcpResults source) { - this(source == null ? null : source.toStaticIpConfiguration()); - if (source != null) { - serverAddress = source.serverAddress; - vendorInfo = source.vendorInfo; - leaseDuration = source.leaseDuration; - mtu = source.mtu; - serverHostName = source.serverHostName; - captivePortalApiUrl = source.captivePortalApiUrl; - } - } - - /** - * @see StaticIpConfiguration#getRoutes(String) - * @hide - */ - public List<RouteInfo> getRoutes(String iface) { - return toStaticIpConfiguration().getRoutes(iface); - } - - /** - * Test if this DHCP lease includes vendor hint that network link is - * metered, and sensitive to heavy data transfers. - */ - public boolean hasMeteredHint() { - if (vendorInfo != null) { - return vendorInfo.contains("ANDROID_METERED"); - } else { - return false; - } - } - - public void clear() { - ipAddress = null; - gateway = null; - dnsServers.clear(); - domains = null; - serverAddress = null; - vendorInfo = null; - leaseDuration = 0; - mtu = 0; - serverHostName = null; - captivePortalApiUrl = null; - } - - @Override - public String toString() { - StringBuffer str = new StringBuffer(super.toString()); - - str.append(" DHCP server ").append(serverAddress); - str.append(" Vendor info ").append(vendorInfo); - str.append(" lease ").append(leaseDuration).append(" seconds"); - if (mtu != 0) str.append(" MTU ").append(mtu); - str.append(" Servername ").append(serverHostName); - if (captivePortalApiUrl != null) { - str.append(" CaptivePortalApiUrl ").append(captivePortalApiUrl); - } - - return str.toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) return true; - - if (!(obj instanceof DhcpResults)) return false; - - DhcpResults target = (DhcpResults)obj; - - return toStaticIpConfiguration().equals(target.toStaticIpConfiguration()) - && Objects.equals(serverAddress, target.serverAddress) - && Objects.equals(vendorInfo, target.vendorInfo) - && Objects.equals(serverHostName, target.serverHostName) - && leaseDuration == target.leaseDuration - && mtu == target.mtu - && Objects.equals(captivePortalApiUrl, target.captivePortalApiUrl); - } - - /** - * Implement the Parcelable interface - */ - public static final @android.annotation.NonNull Creator<DhcpResults> CREATOR = - new Creator<DhcpResults>() { - public DhcpResults createFromParcel(Parcel in) { - return readFromParcel(in); - } - - public DhcpResults[] newArray(int size) { - return new DhcpResults[size]; - } - }; - - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { - toStaticIpConfiguration().writeToParcel(dest, flags); - dest.writeInt(leaseDuration); - dest.writeInt(mtu); - InetAddressUtils.parcelInetAddress(dest, serverAddress, flags); - dest.writeString(vendorInfo); - dest.writeString(serverHostName); - dest.writeString(captivePortalApiUrl); - } - - @Override - public int describeContents() { - return 0; - } - - private static DhcpResults readFromParcel(Parcel in) { - final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in); - final DhcpResults dhcpResults = new DhcpResults(s); - dhcpResults.leaseDuration = in.readInt(); - dhcpResults.mtu = in.readInt(); - dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in); - dhcpResults.vendorInfo = in.readString(); - dhcpResults.serverHostName = in.readString(); - dhcpResults.captivePortalApiUrl = in.readString(); - return dhcpResults; - } - - // Utils for jni population - false on success - // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon. - public boolean setIpAddress(String addrString, int prefixLength) { - try { - Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString); - ipAddress = new LinkAddress(addr, prefixLength); - } catch (IllegalArgumentException|ClassCastException e) { - Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength); - return true; - } - return false; - } - - public boolean setGateway(String addrString) { - try { - gateway = InetAddresses.parseNumericAddress(addrString); - } catch (IllegalArgumentException e) { - Log.e(TAG, "setGateway failed with addrString " + addrString); - return true; - } - return false; - } - - public boolean addDns(String addrString) { - if (TextUtils.isEmpty(addrString) == false) { - try { - dnsServers.add(InetAddresses.parseNumericAddress(addrString)); - } catch (IllegalArgumentException e) { - Log.e(TAG, "addDns failed with addrString " + addrString); - return true; - } - } - return false; - } - - public LinkAddress getIpAddress() { - return ipAddress; - } - - public void setIpAddress(LinkAddress ipAddress) { - this.ipAddress = ipAddress; - } - - public InetAddress getGateway() { - return gateway; - } - - public void setGateway(InetAddress gateway) { - this.gateway = gateway; - } - - public List<InetAddress> getDnsServers() { - return dnsServers; - } - - /** - * Add a DNS server to this configuration. - */ - public void addDnsServer(InetAddress server) { - dnsServers.add(server); - } - - public String getDomains() { - return domains; - } - - public void setDomains(String domains) { - this.domains = domains; - } - - public Inet4Address getServerAddress() { - return serverAddress; - } - - public void setServerAddress(Inet4Address addr) { - serverAddress = addr; - } - - public int getLeaseDuration() { - return leaseDuration; - } - - public void setLeaseDuration(int duration) { - leaseDuration = duration; - } - - public String getVendorInfo() { - return vendorInfo; - } - - public void setVendorInfo(String info) { - vendorInfo = info; - } - - public int getMtu() { - return mtu; - } - - public void setMtu(int mtu) { - this.mtu = mtu; - } - - public String getCaptivePortalApiUrl() { - return captivePortalApiUrl; - } - - public void setCaptivePortalApiUrl(String url) { - captivePortalApiUrl = url; - } -} diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 6284f56c8258..dc241066a60a 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -72,9 +72,9 @@ interface INetworkPolicyManager { SubscriptionPlan getSubscriptionPlan(in NetworkTemplate template); void notifyStatsProviderWarningOrLimitReached(); SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage); - void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage); + void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, long expirationDurationMillis, String callingPackage); String getSubscriptionPlansOwner(int subId); - void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long timeoutMillis, String callingPackage); + void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long expirationDurationMillis, String callingPackage); void factoryReset(String subscriber); diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 596f4317dce3..714227d87aeb 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -338,7 +338,9 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST); out.writeInt(template.getMatchRule()); - BackupUtils.writeString(out, template.getSubscriberIds().iterator().next()); + final Set<String> subscriberIds = template.getSubscriberIds(); + BackupUtils.writeString(out, subscriberIds.isEmpty() + ? null : subscriberIds.iterator().next()); BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty() ? null : template.getWifiNetworkKeys().iterator().next()); out.writeInt(template.getMeteredness()); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 9122adfece53..d8f098eb880b 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -482,8 +482,8 @@ public class NetworkPolicyManager { * @param networkTypes the network types this override applies to. If no * network types are specified, override values will be ignored. * {@see TelephonyManager#getAllNetworkTypes()} - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the + * @param expirationDurationMillis the duration after which the requested override + * will be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first * @param callingPackage the name of the package making the call. @@ -491,11 +491,11 @@ public class NetworkPolicyManager { */ public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask, @SubscriptionOverrideMask int overrideValue, - @NonNull @Annotation.NetworkType int[] networkTypes, long timeoutMillis, + @NonNull @Annotation.NetworkType int[] networkTypes, long expirationDurationMillis, @NonNull String callingPackage) { try { mService.setSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes, - timeoutMillis, callingPackage); + expirationDurationMillis, callingPackage); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -506,13 +506,16 @@ public class NetworkPolicyManager { * * @param subId the subscriber this relationship applies to. * @param plans the list of plans. + * @param expirationDurationMillis the duration after which the subscription plans + * will be automatically cleared, or {@code 0} to leave the plans until + * explicitly cleared, or the next reboot, whichever happens first * @param callingPackage the name of the package making the call * @hide */ public void setSubscriptionPlans(int subId, @NonNull SubscriptionPlan[] plans, - @NonNull String callingPackage) { + long expirationDurationMillis, @NonNull String callingPackage) { try { - mService.setSubscriptionPlans(subId, plans, callingPackage); + mService.setSubscriptionPlans(subId, plans, expirationDurationMillis, callingPackage); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index d9c9a2b55abd..bc7fb789b538 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -63,7 +63,7 @@ interface IUserManager { boolean isUserTypeEnabled(in String userType); boolean canAddMoreUsersOfType(in String userType); int getRemainingCreatableUserCount(in String userType); - int getRemainingCreatableProfileCount(in String userType, int userId, boolean allowedToRemoveOne); + int getRemainingCreatableProfileCount(in String userType, int userId); boolean canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne); boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne); UserInfo getProfileParent(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 7b8d34b3b570..2bd1dbb238e8 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -4055,9 +4055,6 @@ public class UserManager { * <p>Note that is applicable to any profile type (currently not including Restricted profiles). * * @param userType the type of profile, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. - * @param allowedToRemoveOne whether removing an existing profile of given type -if there is- - * from the context user to make up space should be taken into account - * for the calculation. * @return how many additional profiles can be created. * @hide */ @@ -4068,13 +4065,11 @@ public class UserManager { android.Manifest.permission.QUERY_USERS }) @UserHandleAware - public int getRemainingCreatableProfileCount(@NonNull String userType, - boolean allowedToRemoveOne) { + public int getRemainingCreatableProfileCount(@NonNull String userType) { Objects.requireNonNull(userType, "userType must not be null"); try { // TODO(b/142482943): Perhaps let the following code apply to restricted users too. - return mService.getRemainingCreatableProfileCount(userType, mUserId, - allowedToRemoveOne); + return mService.getRemainingCreatableProfileCount(userType, mUserId); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ee6f9c033271..8538b7d6be95 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6094,11 +6094,9 @@ public final class Settings { } /** @hide */ - @SystemApi - @Nullable - @SuppressLint("VisiblySynchronized") - public static String getStringForUser(@NonNull ContentResolver resolver, - @NonNull String name, int userHandle) { + @UnsupportedAppUsage + public static String getStringForUser(ContentResolver resolver, String name, + int userHandle) { if (MOVED_TO_GLOBAL.contains(name)) { Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + " to android.provider.Settings.Global."); @@ -6330,9 +6328,8 @@ public final class Settings { } /** @hide */ - @SystemApi - public static int getIntForUser(@NonNull ContentResolver cr, @NonNull String name, - int def, int userHandle) { + @UnsupportedAppUsage + public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) { String v = getStringForUser(cr, name, userHandle); return parseIntSettingWithDefault(v, def); } @@ -17325,6 +17322,12 @@ public final class Settings { "clockwork_long_press_to_assistant_enabled"; /* + * Whether the device has Cooldown Mode enabled. + * @hide + */ + public static final String COOLDOWN_MODE_ON = "cooldown_mode_on"; + + /* * Whether the device has Wet Mode/ Touch Lock Mode enabled. * @hide */ diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 34e35d4512b9..3ff0161b80d5 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -1425,25 +1425,6 @@ public final class Telephony { public static final String KEY_TYPE = "key_type"; /** - * MVNO type: - * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}. - * <P> Type: TEXT </P> - */ - public static final String MVNO_TYPE = "mvno_type"; - - /** - * MVNO data. - * Use the following examples. - * <ul> - * <li>SPN: A MOBILE, BEN NL, ...</li> - * <li>IMSI: 302720x94, 2060188, ...</li> - * <li>GID: 4E, 33, ...</li> - * </ul> - * <P> Type: TEXT </P> - */ - public static final String MVNO_MATCH_DATA = "mvno_match_data"; - - /** * The carrier public key that is used for the IMSI encryption. * <P> Type: TEXT </P> */ @@ -1470,6 +1451,11 @@ public final class Telephony { public static final String LAST_MODIFIED = "last_modified"; /** + * Carrier ID of the operetor. + * <P> Type: TEXT </P> + */ + public static final String CARRIER_ID = "carrier_id"; + /** * The {@code content://} style URL for this table. */ @NonNull diff --git a/core/java/android/service/games/IGameSessionController.aidl b/core/java/android/service/games/IGameSessionController.aidl index 84311dc0aedf..fd994044775f 100644 --- a/core/java/android/service/games/IGameSessionController.aidl +++ b/core/java/android/service/games/IGameSessionController.aidl @@ -24,6 +24,6 @@ import com.android.internal.infra.AndroidFuture; */ oneway interface IGameSessionController { void takeScreenshot(int taskId, in AndroidFuture gameScreenshotResultFuture); - @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)") void restartGame(in int taskId); } diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl index 7c79b1ae15de..986a41c64053 100644 --- a/core/java/android/speech/IRecognitionListener.aidl +++ b/core/java/android/speech/IRecognitionListener.aidl @@ -78,6 +78,24 @@ oneway interface IRecognitionListener { void onPartialResults(in Bundle results); /** + * Called for each ready segment of a recognition request. To request segmented speech results + * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. The callback might be called + * any number of times between {@link #onBeginningOfSpeech()} and + * {@link #onEndOfSegmentedSession()}. + * + * @param segmentResults the returned results. To retrieve the results in + * ArrayList<String> format use {@link Bundle#getStringArrayList(String)} with + * {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter + */ + void onSegmentResults(in Bundle results); + + /** + * Called at the end of a segmented recognition request. To request segmented speech results + * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. + */ + void onEndOfSegmentedSession(); + + /** * Reserved for adding future events. * * @param eventType the type of the occurred event diff --git a/core/java/android/speech/RecognitionListener.java b/core/java/android/speech/RecognitionListener.java index c94b60f847f4..64fd09ff7faf 100644 --- a/core/java/android/speech/RecognitionListener.java +++ b/core/java/android/speech/RecognitionListener.java @@ -15,6 +15,7 @@ */ package android.speech; +import android.annotation.NonNull; import android.content.Intent; import android.os.Bundle; @@ -69,7 +70,13 @@ public interface RecognitionListener { /** * Called when recognition results are ready. - * + * + * <p> + * Called with the results for the full speech since {@link #onReadyForSpeech(Bundle)}. + * To get recognition results in segments rather than for the full session see + * {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. + * </p> + * * @param results the recognition results. To retrieve the results in {@code * ArrayList<String>} format use {@link Bundle#getStringArrayList(String)} with * {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter. A float array of @@ -92,6 +99,24 @@ public interface RecognitionListener { void onPartialResults(Bundle partialResults); /** + * Called for each ready segment of a recognition request. To request segmented speech results + * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. The callback might be called + * any number of times between {@link #onReadyForSpeech(Bundle)} and + * {@link #onEndOfSegmentedSession()}. + * + * @param segmentResults the returned results. To retrieve the results in + * ArrayList<String> format use {@link Bundle#getStringArrayList(String)} with + * {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter + */ + default void onSegmentResults(@NonNull Bundle segmentResults) {} + + /** + * Called at the end of a segmented recognition request. To request segmented speech results + * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. + */ + default void onEndOfSegmentedSession() {} + + /** * Reserved for adding future events. * * @param eventType the type of the occurred event diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 5dbbc045077e..08136761f75c 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -427,6 +427,26 @@ public abstract class RecognitionService extends Service { } /** + * The service should call this method for each ready segment of a long recognition session. + * + * @param results the recognition results. To retrieve the results in {@code + * ArrayList<String>} format use {@link Bundle#getStringArrayList(String)} with + * {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter + */ + @SuppressLint({"CallbackMethodName", "RethrowRemoteException"}) + public void segmentResults(@NonNull Bundle results) throws RemoteException { + mListener.onSegmentResults(results); + } + + /** + * The service should call this method to end a segmented session. + */ + @SuppressLint({"CallbackMethodName", "RethrowRemoteException"}) + public void endOfSegmentedSession() throws RemoteException { + mListener.onEndOfSegmentedSession(); + } + + /** * Return the Linux uid assigned to the process that sent you the current transaction that * is being processed. This is obtained from {@link Binder#getCallingUid()}. */ diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index 3183f15fe16c..271e3072c4d9 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -426,4 +426,16 @@ public class RecognizerIntent { * */ public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE"; + + /** + * Optional boolean, when true and supported by the recognizer implementation it will split + * the recognition results in segments, returned via + * {@link RecognitionListener#onSegmentResults(Bundle)} and terminate the session with + * {@link RecognitionListener#onEndOfSegmentedSession()}. There will be no call to + * {@link RecognitionListener#onResults(Bundle)}. Callers can use + * {@link #EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS} and + * {@link #EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS} to tune how long the segments + * will be. Defaults to false. + */ + public static final String EXTRA_SEGMENT_SESSION = "android.speech.extra.SEGMENT_SESSION"; } diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index 71c1e882a1f6..502558e355e6 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -768,6 +768,8 @@ public class SpeechRecognizer { private static final int MSG_PARTIAL_RESULTS = 7; private static final int MSG_RMS_CHANGED = 8; private static final int MSG_ON_EVENT = 9; + private static final int MSG_SEGMENT_RESULTS = 10; + private static final int MSG_SEGMENT_END_SESSION = 11; private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) { @Override @@ -803,6 +805,12 @@ public class SpeechRecognizer { case MSG_ON_EVENT: mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj); break; + case MSG_SEGMENT_RESULTS: + mInternalListener.onSegmentResults((Bundle) msg.obj); + break; + case MSG_SEGMENT_END_SESSION: + mInternalListener.onEndOfSegmentedSession(); + break; } } }; @@ -839,6 +847,14 @@ public class SpeechRecognizer { Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget(); } + public void onSegmentResults(final Bundle bundle) { + Message.obtain(mInternalHandler, MSG_SEGMENT_RESULTS, bundle).sendToTarget(); + } + + public void onEndOfSegmentedSession() { + Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget(); + } + public void onEvent(final int eventType, final Bundle params) { Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params) .sendToTarget(); diff --git a/core/java/android/view/OnBackInvokedDispatcher.java b/core/java/android/view/OnBackInvokedDispatcher.java index f3ca531f2a42..5c4ee89bfbd3 100644 --- a/core/java/android/view/OnBackInvokedDispatcher.java +++ b/core/java/android/view/OnBackInvokedDispatcher.java @@ -17,8 +17,13 @@ package android.view; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.annotation.TestApi; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.os.Build; import java.lang.annotation.Retention; @@ -32,13 +37,29 @@ import java.lang.annotation.RetentionPolicy; * Attribute updates are proactively pushed to the window manager if they change the dispatch * target (a.k.a. the callback to be invoked next), or its behavior. */ -public abstract class OnBackInvokedDispatcher { +public interface OnBackInvokedDispatcher { + /** + * Enables dispatching the "back" action via {@link android.view.OnBackInvokedDispatcher}. + * + * When enabled, the following APIs are no longer invoked: + * <ul> + * <li> {@link android.app.Activity#onBackPressed} + * <li> {@link android.app.Dialog#onBackPressed} + * <li> {@link android.view.KeyEvent#KEYCODE_BACK} is no longer dispatched. + * </ul> + * + * @hide + */ + @TestApi + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; /** @hide */ - public static final String TAG = "OnBackInvokedDispatcher"; + String TAG = "OnBackInvokedDispatcher"; /** @hide */ - public static final boolean DEBUG = Build.isDebuggable(); + boolean DEBUG = Build.isDebuggable(); /** @hide */ @IntDef({ @@ -46,18 +67,26 @@ public abstract class OnBackInvokedDispatcher { PRIORITY_OVERLAY, }) @Retention(RetentionPolicy.SOURCE) - public @interface Priority{} + @interface Priority{} /** * Priority level of {@link OnBackInvokedCallback}s for overlays such as menus and * navigation drawers that should receive back dispatch before non-overlays. */ - public static final int PRIORITY_OVERLAY = 1000000; + int PRIORITY_OVERLAY = 1000000; /** * Default priority level of {@link OnBackInvokedCallback}s. */ - public static final int PRIORITY_DEFAULT = 0; + int PRIORITY_DEFAULT = 0; + + /** + * Priority level of {@link OnBackInvokedCallback}s registered by the system. + * + * System back animation will play when the callback to receive dispatch has this priority. + * @hide + */ + int PRIORITY_SYSTEM = -1; /** * Registers a {@link OnBackInvokedCallback}. @@ -69,10 +98,11 @@ public abstract class OnBackInvokedDispatcher { * registered, the existing instance (no matter its priority) will be * unregistered and registered again. * @param priority The priority of the callback. + * @throws {@link IllegalArgumentException} if the priority is negative. */ @SuppressLint("SamShouldBeLast") - public abstract void registerOnBackInvokedCallback( - @NonNull OnBackInvokedCallback callback, @Priority int priority); + void registerOnBackInvokedCallback( + @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority); /** * Unregisters a {@link OnBackInvokedCallback}. @@ -80,5 +110,20 @@ public abstract class OnBackInvokedDispatcher { * @param callback The callback to be unregistered. Does nothing if the callback has not been * registered. */ - public abstract void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback); + void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback); + + /** + * Returns the most prioritized callback to receive back dispatch next. + * @hide + */ + @Nullable + default OnBackInvokedCallback getTopCallback() { + return null; + } + + /** + * Registers a {@link OnBackInvokedCallback} with system priority. + * @hide + */ + default void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3d8653554efd..ee4a934482db 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -317,6 +317,11 @@ public final class ViewRootImpl implements ViewParent, */ private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(); + /** + * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events + * to view root for apps using legacy back behavior. + */ + private OnBackInvokedCallback mCompatOnBackInvokedCallback; /** * Callback for notifying about global configuration changes. @@ -1190,6 +1195,14 @@ public final class ViewRootImpl implements ViewParent, mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame); setFrame(mTmpFrames.frame); registerBackCallbackOnWindow(); + if (WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) { + // For apps requesting legacy back behavior, we add a compat callback that + // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views. + // This way from system point of view, these apps are providing custom + // {@link OnBackInvokedCallback}s, and will not play system back animations + // for them. + registerCompatOnBackInvokedCallback(); + } if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null; @@ -5931,7 +5944,7 @@ public final class ViewRootImpl implements ViewParent, } } - private boolean isBack(InputEvent event) { + boolean isBack(InputEvent event) { if (event instanceof KeyEvent) { return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK; } else { @@ -6471,6 +6484,19 @@ public final class ViewRootImpl implements ViewParent, return FINISH_NOT_HANDLED; } + if (isBack(event) + && mContext != null + && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) { + // Invoke the appropriate {@link OnBackInvokedCallback} if the new back + // navigation should be used, and the key event is not handled by anything else. + OnBackInvokedCallback topCallback = + getOnBackInvokedDispatcher().getTopCallback(); + if (topCallback != null) { + topCallback.onBackInvoked(); + return FINISH_HANDLED; + } + } + // This dispatch is for windows that don't have a Window.Callback. Otherwise, // the Window.Callback usually will have already called this (see // DecorView.superDispatchKeyEvent) leaving this call a no-op. @@ -8414,6 +8440,7 @@ public final class ViewRootImpl implements ViewParent, mAdded = false; } + unregisterCompatOnBackInvokedCallback(); mOnBackInvokedDispatcher.detachFromWindow(); WindowManagerGlobal.getInstance().doRemoveView(this); } @@ -10782,6 +10809,38 @@ public final class ViewRootImpl implements ViewParent, mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow); } + private void sendBackKeyEvent(int action) { + long when = SystemClock.uptimeMillis(); + final KeyEvent ev = new KeyEvent(when, when, action, + KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, + KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, + InputDevice.SOURCE_KEYBOARD); + + ev.setDisplayId(mContext.getDisplay().getDisplayId()); + if (mView != null) { + mView.dispatchKeyEvent(ev); + } + } + + private void registerCompatOnBackInvokedCallback() { + mCompatOnBackInvokedCallback = new OnBackInvokedCallback() { + @Override + public void onBackInvoked() { + sendBackKeyEvent(KeyEvent.ACTION_DOWN); + sendBackKeyEvent(KeyEvent.ACTION_UP); + } + }; + mOnBackInvokedDispatcher.registerOnBackInvokedCallback( + mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT); + } + + private void unregisterCompatOnBackInvokedCallback() { + if (mCompatOnBackInvokedCallback != null) { + mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mCompatOnBackInvokedCallback); + } + } + @Override public void setTouchableRegion(Region r) { if (r != null) { diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index a427ab8fe837..cd8dd86b8e02 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -553,8 +553,20 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par public static final int TYPE_ASSIST_READING_CONTEXT = 0x01000000; /** - * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: - * The type of change is not defined. + * Represents a change in the speech state defined by the content-change types. A change in the + * speech state occurs when another service is either speaking or listening for human speech. + * This event helps avoid conflicts where two services want to speak or one listens + * when another speaks. + * @see #SPEECH_STATE_SPEAKING_START + * @see #SPEECH_STATE_SPEAKING_END + * @see #SPEECH_STATE_LISTENING_START + * @see #SPEECH_STATE_LISTENING_END + */ + public static final int TYPE_SPEECH_STATE_CHANGE = 0x02000000; + + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: The type of change is not + * defined. */ public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000; @@ -641,6 +653,27 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200; + /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */ + public static final int SPEECH_STATE_SPEAKING_START = 0x00000001; + + /** + * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer + * speaking. + */ + public static final int SPEECH_STATE_SPEAKING_END = 0x00000002; + + /** + * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is listening to the + * microphone. + */ + public static final int SPEECH_STATE_LISTENING_START = 0x00000004; + + /** + * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer + * listening to the microphone. + */ + public static final int SPEECH_STATE_LISTENING_END = 0x00000008; + /** * Change type for {@link #TYPE_WINDOWS_CHANGED} event: * The window was added. @@ -730,50 +763,69 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "CONTENT_CHANGE_TYPE_" }, + @IntDef( + flag = true, + prefix = {"CONTENT_CHANGE_TYPE_"}, value = { - CONTENT_CHANGE_TYPE_UNDEFINED, - CONTENT_CHANGE_TYPE_SUBTREE, - CONTENT_CHANGE_TYPE_TEXT, - CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION, - CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, - CONTENT_CHANGE_TYPE_PANE_TITLE, - CONTENT_CHANGE_TYPE_PANE_APPEARED, - CONTENT_CHANGE_TYPE_PANE_DISAPPEARED, - CONTENT_CHANGE_TYPE_DRAG_STARTED, - CONTENT_CHANGE_TYPE_DRAG_DROPPED, - CONTENT_CHANGE_TYPE_DRAG_CANCELLED + CONTENT_CHANGE_TYPE_UNDEFINED, + CONTENT_CHANGE_TYPE_SUBTREE, + CONTENT_CHANGE_TYPE_TEXT, + CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION, + CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, + CONTENT_CHANGE_TYPE_PANE_TITLE, + CONTENT_CHANGE_TYPE_PANE_APPEARED, + CONTENT_CHANGE_TYPE_PANE_DISAPPEARED, + CONTENT_CHANGE_TYPE_DRAG_STARTED, + CONTENT_CHANGE_TYPE_DRAG_DROPPED, + CONTENT_CHANGE_TYPE_DRAG_CANCELLED, }) public @interface ContentChangeTypes {} /** @hide */ - @IntDef(flag = true, prefix = { "TYPE_" }, value = { - TYPE_VIEW_CLICKED, - TYPE_VIEW_LONG_CLICKED, - TYPE_VIEW_SELECTED, - TYPE_VIEW_FOCUSED, - TYPE_VIEW_TEXT_CHANGED, - TYPE_WINDOW_STATE_CHANGED, - TYPE_NOTIFICATION_STATE_CHANGED, - TYPE_VIEW_HOVER_ENTER, - TYPE_VIEW_HOVER_EXIT, - TYPE_TOUCH_EXPLORATION_GESTURE_START, - TYPE_TOUCH_EXPLORATION_GESTURE_END, - TYPE_WINDOW_CONTENT_CHANGED, - TYPE_VIEW_SCROLLED, - TYPE_VIEW_TEXT_SELECTION_CHANGED, - TYPE_ANNOUNCEMENT, - TYPE_VIEW_ACCESSIBILITY_FOCUSED, - TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, - TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, - TYPE_GESTURE_DETECTION_START, - TYPE_GESTURE_DETECTION_END, - TYPE_TOUCH_INTERACTION_START, - TYPE_TOUCH_INTERACTION_END, - TYPE_WINDOWS_CHANGED, - TYPE_VIEW_CONTEXT_CLICKED, - TYPE_ASSIST_READING_CONTEXT - }) + @Retention(RetentionPolicy.SOURCE) + @IntDef( + flag = true, + prefix = {"SPEECH_STATE_"}, + value = { + SPEECH_STATE_SPEAKING_START, + SPEECH_STATE_SPEAKING_END, + SPEECH_STATE_LISTENING_START, + SPEECH_STATE_LISTENING_END + }) + public @interface SpeechStateChangeTypes {} + + /** @hide */ + @IntDef( + flag = true, + prefix = {"TYPE_"}, + value = { + TYPE_VIEW_CLICKED, + TYPE_VIEW_LONG_CLICKED, + TYPE_VIEW_SELECTED, + TYPE_VIEW_FOCUSED, + TYPE_VIEW_TEXT_CHANGED, + TYPE_WINDOW_STATE_CHANGED, + TYPE_NOTIFICATION_STATE_CHANGED, + TYPE_VIEW_HOVER_ENTER, + TYPE_VIEW_HOVER_EXIT, + TYPE_TOUCH_EXPLORATION_GESTURE_START, + TYPE_TOUCH_EXPLORATION_GESTURE_END, + TYPE_WINDOW_CONTENT_CHANGED, + TYPE_VIEW_SCROLLED, + TYPE_VIEW_TEXT_SELECTION_CHANGED, + TYPE_ANNOUNCEMENT, + TYPE_VIEW_ACCESSIBILITY_FOCUSED, + TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, + TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + TYPE_GESTURE_DETECTION_START, + TYPE_GESTURE_DETECTION_END, + TYPE_TOUCH_INTERACTION_START, + TYPE_TOUCH_INTERACTION_END, + TYPE_WINDOWS_CHANGED, + TYPE_VIEW_CONTEXT_CLICKED, + TYPE_ASSIST_READING_CONTEXT, + TYPE_SPEECH_STATE_CHANGE + }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} @@ -814,6 +866,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par int mAction; int mContentChangeTypes; int mWindowChangeTypes; + int mSpeechStateChangeTypes; /** * The stack trace describing where this event originated from on the app side. @@ -867,6 +920,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mMovementGranularity = event.mMovementGranularity; mAction = event.mAction; mContentChangeTypes = event.mContentChangeTypes; + mSpeechStateChangeTypes = event.mSpeechStateChangeTypes; mWindowChangeTypes = event.mWindowChangeTypes; mEventTime = event.mEventTime; mPackageName = event.mPackageName; @@ -1008,6 +1062,51 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par } /** + * Gets the speech state signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event + * + * @see #SPEECH_STATE_SPEAKING_START + * @see #SPEECH_STATE_SPEAKING_END + * @see #SPEECH_STATE_LISTENING_START + * @see #SPEECH_STATE_LISTENING_END + */ + public int getSpeechStateChangeTypes() { + return mSpeechStateChangeTypes; + } + + private static String speechStateChangedTypesToString(int types) { + return BitUtils.flagsToString( + types, AccessibilityEvent::singleSpeechStateChangeTypeToString); + } + + private static String singleSpeechStateChangeTypeToString(int type) { + switch (type) { + case SPEECH_STATE_SPEAKING_START: + return "SPEECH_STATE_SPEAKING_START"; + case SPEECH_STATE_LISTENING_START: + return "SPEECH_STATE_LISTENING_START"; + case SPEECH_STATE_SPEAKING_END: + return "SPEECH_STATE_SPEAKING_END"; + case SPEECH_STATE_LISTENING_END: + return "SPEECH_STATE_LISTENING_END"; + default: + return Integer.toHexString(type); + } + } + + /** + * Sets the speech state type signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event + * + * @see #SPEECH_STATE_SPEAKING_START + * @see #SPEECH_STATE_SPEAKING_END + * @see #SPEECH_STATE_LISTENING_START + * @see #SPEECH_STATE_LISTENING_END + */ + public void setSpeechStateChangeTypes(int state) { + enforceNotSealed(); + mSpeechStateChangeTypes = state; + } + + /** * Get the bit mask of change types signaled by a {@link #TYPE_WINDOWS_CHANGED} event. A * single event may represent multiple change types. * @@ -1239,6 +1338,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mAction = 0; mContentChangeTypes = 0; mWindowChangeTypes = 0; + mSpeechStateChangeTypes = 0; mPackageName = null; mEventTime = 0; if (mRecords != null) { @@ -1261,6 +1361,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mAction = parcel.readInt(); mContentChangeTypes = parcel.readInt(); mWindowChangeTypes = parcel.readInt(); + mSpeechStateChangeTypes = parcel.readInt(); mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); mEventTime = parcel.readLong(); mConnectionId = parcel.readInt(); @@ -1332,6 +1433,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par parcel.writeInt(mAction); parcel.writeInt(mContentChangeTypes); parcel.writeInt(mWindowChangeTypes); + parcel.writeInt(mSpeechStateChangeTypes); TextUtils.writeToParcel(mPackageName, parcel, 0); parcel.writeLong(mEventTime); parcel.writeInt(mConnectionId); @@ -1500,6 +1602,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par case TYPE_WINDOWS_CHANGED: return "TYPE_WINDOWS_CHANGED"; case TYPE_VIEW_CONTEXT_CLICKED: return "TYPE_VIEW_CONTEXT_CLICKED"; case TYPE_ASSIST_READING_CONTEXT: return "TYPE_ASSIST_READING_CONTEXT"; + case TYPE_SPEECH_STATE_CHANGE: return "TYPE_SPEECH_STATE_CHANGE"; default: return Integer.toHexString(eventType); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0fe2ed51beb6..9efa583a894a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10821,8 +10821,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && mSavedMarqueeModeLayout.getLineWidth(0) > width)); } + /** + * @hide + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private void startMarquee() { + protected void startMarquee() { // Do not ellipsize EditText if (getKeyListener() != null) return; @@ -10848,7 +10851,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void stopMarquee() { + /** + * @hide + */ + protected void stopMarquee() { if (mMarquee != null && !mMarquee.isStopped()) { mMarquee.stop(); } diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java index 509bbd4de389..4de977a91d05 100644 --- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java +++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java @@ -42,7 +42,7 @@ import java.util.List; * * @hide */ -public class ProxyOnBackInvokedDispatcher extends OnBackInvokedDispatcher { +public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher { /** * List of pair representing an {@link OnBackInvokedCallback} and its associated priority. @@ -60,14 +60,16 @@ public class ProxyOnBackInvokedDispatcher extends OnBackInvokedDispatcher { Log.v(TAG, String.format("Pending register %s. Actual=%s", callback, mActualDispatcherOwner)); } - synchronized (mLock) { - mCallbacks.add(Pair.create(callback, priority)); - if (mActualDispatcherOwner != null) { - mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback( - callback, priority); - } - + if (priority < 0) { + throw new IllegalArgumentException("Application registered OnBackInvokedCallback " + + "cannot have negative priority. Priority: " + priority); } + registerOnBackInvokedCallbackUnchecked(callback, priority); + } + + @Override + public void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { + registerOnBackInvokedCallbackUnchecked(callback, PRIORITY_SYSTEM); } @Override @@ -82,6 +84,17 @@ public class ProxyOnBackInvokedDispatcher extends OnBackInvokedDispatcher { } } + private void registerOnBackInvokedCallbackUnchecked( + @NonNull OnBackInvokedCallback callback, int priority) { + synchronized (mLock) { + mCallbacks.add(Pair.create(callback, priority)); + if (mActualDispatcherOwner != null) { + mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback( + callback, priority); + } + } + } + /** * Transfers all the pending callbacks to the provided dispatcher. * <p> @@ -99,8 +112,12 @@ public class ProxyOnBackInvokedDispatcher extends OnBackInvokedDispatcher { dispatcher)); } for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) { - dispatcher.registerOnBackInvokedCallback(callbackPair.first, - callbackPair.second); + int priority = callbackPair.second; + if (priority >= 0) { + dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority); + } else { + dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first); + } } mCallbacks.clear(); } diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 29786046e49c..d37d3b42872f 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -18,8 +18,10 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.compat.CompatChanges; import android.os.Handler; import android.os.RemoteException; +import android.os.SystemProperties; import android.util.Log; import android.view.IWindow; import android.view.IWindowSession; @@ -31,7 +33,7 @@ import java.util.HashMap; import java.util.TreeMap; /** - * Provides window based implementation of {@link OnBackInvokedDispatcher}. + * Provides window based implementation of {@link android.view.OnBackInvokedDispatcher}. * * Callbacks with higher priorities receive back dispatching first. * Within the same priority, callbacks receive back dispatching in the reverse order @@ -39,16 +41,19 @@ import java.util.TreeMap; * * When the top priority callback is updated, the new callback is propagated to the Window Manager * if the window the instance is associated with has been attached. It is allowed to register / - * unregister {@link OnBackInvokedCallback}s before the window is attached, although callbacks - * will not receive dispatches until window attachment. + * unregister {@link android.view.OnBackInvokedCallback}s before the window is attached, although + * callbacks will not receive dispatches until window attachment. * * @hide */ -public class WindowOnBackInvokedDispatcher extends OnBackInvokedDispatcher { +public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { private IWindowSession mWindowSession; private IWindow mWindow; private static final String TAG = "WindowOnBackDispatcher"; private static final boolean DEBUG = false; + private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability"; + private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties + .getInt(BACK_PREDICTABILITY_PROP, 0) > 0; /** The currently most prioritized callback. */ @Nullable @@ -82,6 +87,15 @@ public class WindowOnBackInvokedDispatcher extends OnBackInvokedDispatcher { @Override public void registerOnBackInvokedCallback( @NonNull OnBackInvokedCallback callback, @Priority int priority) { + if (priority < 0) { + throw new IllegalArgumentException("Application registered OnBackInvokedCallback " + + "cannot have negative priority. Priority: " + priority); + } + registerOnBackInvokedCallbackUnchecked(callback, priority); + } + + private void registerOnBackInvokedCallbackUnchecked( + @NonNull OnBackInvokedCallback callback, @Priority int priority) { if (!mOnBackInvokedCallbacks.containsKey(priority)) { mOnBackInvokedCallbacks.put(priority, new ArrayList<>()); } @@ -120,6 +134,11 @@ public class WindowOnBackInvokedDispatcher extends OnBackInvokedDispatcher { } } + @Override + public void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { + registerOnBackInvokedCallbackUnchecked(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM); + } + /** Clears all registered callbacks on the instance. */ public void clear() { mAllCallbacks.clear(); @@ -198,4 +217,21 @@ public class WindowOnBackInvokedDispatcher extends OnBackInvokedDispatcher { Handler.getMain().post(() -> mCallback.onBackInvoked()); } } + + @Override + public OnBackInvokedCallback getTopCallback() { + return mTopCallback == null ? null : mTopCallback.getCallback(); + } + + /** + * Returns if the legacy back behavior should be used. + * + * Legacy back behavior dispatches KEYCODE_BACK instead of invoking the application registered + * {@link android.view.OnBackInvokedCallback}. + * + */ + public static boolean shouldUseLegacyBack() { + return !CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME) + || !IS_BACK_PREDICTABILITY_ENABLED; + } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 8bb9a0a0d6ff..955f46b977b7 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -309,8 +309,6 @@ cc_library_shared { "libdl_android", "libtimeinstate", "server_configurable_flags", - // TODO: delete when ConnectivityT moves to APEX. - "libframework-connectivity-tiramisu-jni", ], export_shared_lib_headers: [ // our headers include libnativewindow's public headers diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 61b91ddaa2e7..13ca13322cc7 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -873,7 +873,7 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, const char* exceptionToThrow; char msg[128]; // TransactionTooLargeException is a checked exception, only throw from certain methods. - // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION + // TODO(b/28321379): Transaction size is the most common cause for FAILED_TRANSACTION // but it is not the only one. The Binder driver can return BR_FAILED_REPLY // for other reasons also, such as if the transaction is malformed or // refers to an FD that has been closed. We should change the driver @@ -890,8 +890,9 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, exceptionToThrow = (canThrowRemoteException) ? "android/os/DeadObjectException" : "java/lang/RuntimeException"; - snprintf(msg, sizeof(msg)-1, - "Transaction failed on small parcel; remote process probably died"); + snprintf(msg, sizeof(msg) - 1, + "Transaction failed on small parcel; remote process probably died, but " + "this could also be caused by running out of binder buffer space"); } jniThrowException(env, exceptionToThrow, msg); } break; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index aacf700b1168..5efc4db52623 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -202,6 +202,8 @@ static constexpr unsigned int STORAGE_DIR_CHECK_MAX_INTERVAL_US = 1000; */ static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5; +static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn); + /** * A helper class containing accounting information for USAPs. */ @@ -1249,7 +1251,11 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name); auto cePath = StringPrintf("%s/user", volPath.c_str()); auto dePath = StringPrintf("%s/user_de", volPath.c_str()); + // Wait until dir user is created. + WaitUntilDirReady(cePath.c_str(), fail_fn); MountAppDataTmpFs(cePath.c_str(), fail_fn); + // Wait until dir user_de is created. + WaitUntilDirReady(dePath.c_str(), fail_fn); MountAppDataTmpFs(dePath.c_str(), fail_fn); } closedir(dir); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 506a0c09b7c9..74bf152344c3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -978,6 +978,61 @@ android:permissionFlags="softRestricted|immutablyRestricted" android:protectionLevel="dangerous" /> + <!-- Required to be able to read audio files from shared storage. + <p>Protection level: dangerous --> + <permission-group android:name="android.permission-group.READ_MEDIA_AURAL" + android:icon="@drawable/perm_group_read_media_aural" + android:label="@string/permgrouplab_readMediaAural" + android:description="@string/permgroupdesc_readMediaAural" + android:priority="950" /> + + <!-- Allows an application to read audio files from external storage. + <p>This permission is enforced starting in API level + {@link android.os.Build.VERSION_CODES#TIRAMISU}. + For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code + targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission + must not be used and the READ_EXTERNAL_STORAGE permission must be used instead. + <p>Protection level: dangerous --> + <permission android:name="android.permission.READ_MEDIA_AUDIO" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_readMediaAudio" + android:description="@string/permdesc_readMediaAudio" + android:protectionLevel="dangerous" /> + + <!-- Required to be able to read image and video files from shared storage. + <p>Protection level: dangerous --> + <permission-group android:name="android.permission-group.READ_MEDIA_VISUAL" + android:icon="@drawable/perm_group_read_media_visual" + android:label="@string/permgrouplab_readMediaVisual" + android:description="@string/permgroupdesc_readMediaVisual" + android:priority="1000" /> + + <!-- Allows an application to read audio files from external storage. + <p>This permission is enforced starting in API level + {@link android.os.Build.VERSION_CODES#TIRAMISU}. + For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code + targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission + must not be used and the READ_EXTERNAL_STORAGE permission must be used instead. + <p>Protection level: dangerous --> + <permission android:name="android.permission.READ_MEDIA_VIDEO" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_readMediaVideo" + android:description="@string/permdesc_readMediaVideo" + android:protectionLevel="dangerous" /> + + <!-- Allows an application to read image files from external storage. + <p>This permission is enforced starting in API level + {@link android.os.Build.VERSION_CODES#TIRAMISU}. + For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code + targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission + must not be used and the READ_EXTERNAL_STORAGE permission must be used instead. + <p>Protection level: dangerous --> + <permission android:name="android.permission.READ_MEDIA_IMAGE" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_readMediaImage" + android:description="@string/permdesc_readMediaImage" + android:protectionLevel="dangerous" /> + <!-- Allows an application to write to external storage. <p class="note"><strong>Note:</strong> If <em>both</em> your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code diff --git a/core/res/res/drawable/perm_group_read_media_aural.xml b/core/res/res/drawable/perm_group_read_media_aural.xml new file mode 100644 index 000000000000..6fc9c69254cc --- /dev/null +++ b/core/res/res/drawable/perm_group_read_media_aural.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M10,21q-1.65,0 -2.825,-1.175Q6,18.65 6,17q0,-1.65 1.175,-2.825Q8.35,13 10,13q0.575,0 1.063,0.137 0.487,0.138 0.937,0.413V3h6v4h-4v10q0,1.65 -1.175,2.825Q11.65,21 10,21z"/> +</vector>
\ No newline at end of file diff --git a/core/res/res/drawable/perm_group_read_media_visual.xml b/core/res/res/drawable/perm_group_read_media_visual.xml new file mode 100644 index 000000000000..a5db2718c983 --- /dev/null +++ b/core/res/res/drawable/perm_group_read_media_visual.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M9,14h10l-3.45,-4.5 -2.3,3 -1.55,-2zM8,18q-0.825,0 -1.412,-0.587Q6,16.825 6,16L6,4q0,-0.825 0.588,-1.413Q7.175,2 8,2h12q0.825,0 1.413,0.587Q22,3.175 22,4v12q0,0.825 -0.587,1.413Q20.825,18 20,18zM8,16h12L20,4L8,4v12zM4,22q-0.825,0 -1.413,-0.587Q2,20.825 2,20L2,6h2v14h14v2zM8,4v12L8,4z"/> +</vector>
\ No newline at end of file diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 59d6005ba193..54325e590347 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -448,4 +448,7 @@ <color name="accessibility_magnification_background">#F50D60</color> <color name="accessibility_daltonizer_background">#00BCD4</color> <color name="accessibility_color_inversion_background">#546E7A</color> + + <!-- Color of camera light when camera is in use --> + <color name="camera_privacy_light">#FFFFFF</color> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d7ebb0f18c4b..47b4d38cf0ce 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -876,9 +876,19 @@ <string name="permgroupdesc_sms">send and view SMS messages</string> <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permgrouplab_storage">Files and media</string> + <string name="permgrouplab_storage">Files & documents</string> <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permgroupdesc_storage">access photos, media, and files on your device</string> + <string name="permgroupdesc_storage">access files and documents on your device</string> + + <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]--> + <string name="permgrouplab_readMediaAural">Music & other audio</string> + <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]--> + <string name="permgroupdesc_readMediaAural">access audio files on your device</string> + + <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]--> + <string name="permgrouplab_readMediaVisual">Photos & videos</string> + <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]--> + <string name="permgroupdesc_readMediaVisual">access images and video files on your device</string> <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> <string name="permgrouplab_microphone">Microphone</string> @@ -1893,6 +1903,21 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> <string name="permdesc_sdcardRead">Allows the app to read the contents of your shared storage.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permlab_readMediaAudio">read audio files from shared storage</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permdesc_readMediaAudio">Allows the app to read audio files from your shared storage.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permlab_readMediaVideo">read video files from shared storage</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permdesc_readMediaVideo">Allows the app to read video files from your shared storage.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permlab_readMediaImage">read image files from shared storage</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] --> + <string name="permdesc_readMediaImage">Allows the app to read image files from your shared storage.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] --> <string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 33efbce15eea..2b25c3eb099b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4722,4 +4722,6 @@ <java-symbol type="bool" name="config_lowPowerStandbySupported" /> <java-symbol type="bool" name="config_lowPowerStandbyEnabledByDefault" /> <java-symbol type="integer" name="config_lowPowerStandbyNonInteractiveTimeout" /> + + <java-symbol type="color" name="camera_privacy_light"/> </resources> diff --git a/core/tests/bandwidthtests/Android.bp b/core/tests/bandwidthtests/Android.bp index f1ecd45073eb..d0b42f783bef 100644 --- a/core/tests/bandwidthtests/Android.bp +++ b/core/tests/bandwidthtests/Android.bp @@ -23,6 +23,7 @@ package { android_test { name: "BandwidthTests", + defaults: ["framework-connectivity-test-defaults"], // Include all test java files. srcs: ["src/**/*.java"], libs: [ diff --git a/core/tests/benchmarks/Android.bp b/core/tests/benchmarks/Android.bp index 4cd546753dbf..0888776f1683 100644 --- a/core/tests/benchmarks/Android.bp +++ b/core/tests/benchmarks/Android.bp @@ -27,6 +27,7 @@ package { java_library { name: "frameworks-base-core-benchmarks", + defaults: ["framework-connectivity-test-defaults"], installable: true, srcs: ["src/**/*.java"], libs: ["caliper-api-target"], diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt index 3c8f90c9c0f8..6360a2deb544 100644 --- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt +++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt @@ -16,7 +16,9 @@ package android.net +import android.net.NetworkStats.METERED_YES import android.net.NetworkTemplate.MATCH_BLUETOOTH +import android.net.NetworkTemplate.MATCH_CARRIER import android.net.NetworkTemplate.MATCH_ETHERNET import android.net.NetworkTemplate.MATCH_MOBILE import android.net.NetworkTemplate.MATCH_WIFI @@ -39,11 +41,19 @@ class NetworkPolicyTest { @Test fun testTemplateBackupRestore() { assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1))) + NetworkTemplate.Builder(MATCH_WIFI) + .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)) + .build())) assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1))) + NetworkTemplate.Builder(MATCH_MOBILE) + .setSubscriberIds(setOf(TEST_IMSI1)) + .setMeteredness(METERED_YES) + .build())) assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateCarrierMetered(TEST_IMSI1))) + NetworkTemplate.Builder(MATCH_CARRIER) + .setSubscriberIds(setOf(TEST_IMSI1)) + .setMeteredness(METERED_YES) + .build())) } private fun createTestPolicyForTemplate(template: NetworkTemplate): NetworkPolicy { diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java index 6df9002608af..ddc27aacc86f 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java @@ -42,7 +42,7 @@ public class AccessibilityEventTest { // and assertAccessibilityEventCleared /** The number of properties of the {@link AccessibilityEvent} class. */ - private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32; + private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 33; // The number of fields tested in the corresponding CTS AccessibilityRecordTest: // assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord, diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java index c20293b2443b..95225b2e4f39 100644 --- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java @@ -16,6 +16,9 @@ package com.android.internal.os; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -94,7 +97,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)); mStatsRule.setNetworkStats(networkStats); ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, @@ -160,7 +164,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity mStatsRule.setNetworkStats(new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100))); stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 10000, 10000, mNetworkStatsManager); @@ -169,7 +174,8 @@ public class MobileRadioPowerCalculatorTest { BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000); mStatsRule.setNetworkStats(new NetworkStats(12000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 250, 2000, 80, 200)); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200))); stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 12000, 12000, mNetworkStatsManager); @@ -241,7 +247,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)); mStatsRule.setNetworkStats(networkStats); ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, @@ -306,7 +313,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity mStatsRule.setNetworkStats(new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100))); stats.noteModemControllerActivity(null, 10_000_000, 10000, 10000, mNetworkStatsManager); @@ -314,7 +322,8 @@ public class MobileRadioPowerCalculatorTest { BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000); mStatsRule.setNetworkStats(new NetworkStats(12000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 250, 2000, 80, 200)); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200))); stats.noteModemControllerActivity(null, 15_000_000, 12000, 12000, mNetworkStatsManager); 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 a36839910742..f74e72becf4a 100644 --- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java @@ -17,6 +17,9 @@ package com.android.internal.os; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -77,8 +80,12 @@ public class WifiPowerCalculatorTest { private NetworkStats buildNetworkStats(long elapsedRealtime, int rxBytes, int rxPackets, int txBytes, int txPackets) { return new NetworkStats(elapsedRealtime, 1) - .insertEntry("wifi", APP_UID, 0, 0, rxBytes, rxPackets, txBytes, txPackets, 100) - .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111); + .addEntry(new NetworkStats.Entry("wifi", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets, + txBytes, txPackets, 100)) + .addEntry(new NetworkStats.Entry("wifi", Process.WIFI_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1111, 111, + 2222, 22, 111)); } /** Sets up an WifiActivityEnergyInfo for ActivityController-model-based tests. */ diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp index d40d1d2bb6e2..1d5c16c7a536 100644 --- a/core/tests/utillib/Android.bp +++ b/core/tests/utillib/Android.bp @@ -23,6 +23,7 @@ package { java_library { name: "frameworks-core-util-lib", + defaults: ["framework-connectivity-test-defaults"], srcs: ["**/*.java"], diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 92fca3661fbc..88920c865511 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -231,6 +231,18 @@ targetSdk="29"> <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" /> </split-permission> + <split-permission name="android.permission.READ_EXTERNAL_STORAGE" + targetSdk="33"> + <new-permission name="android.permission.READ_MEDIA_AUDIO" /> + </split-permission> + <split-permission name="android.permission.READ_EXTERNAL_STORAGE" + targetSdk="33"> + <new-permission name="android.permission.READ_MEDIA_VIDEO" /> + </split-permission> + <split-permission name="android.permission.READ_EXTERNAL_STORAGE" + targetSdk="33"> + <new-permission name="android.permission.READ_MEDIA_IMAGE" /> + </split-permission> <split-permission name="android.permission.BLUETOOTH" targetSdk="31"> <new-permission name="android.permission.BLUETOOTH_SCAN" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index a331b6eb6750..83c4024e7867 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -334,6 +334,7 @@ applications that come with the platform <permission name="android.permission.MANAGE_ACCESSIBILITY"/> <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> <permission name="android.permission.MANAGE_GAME_MODE"/> + <permission name="android.permission.MANAGE_GAME_ACTIVITY" /> <permission name="android.permission.MANAGE_LOW_POWER_STANDBY" /> <permission name="android.permission.MANAGE_ROLLBACKS"/> <permission name="android.permission.MANAGE_USB"/> @@ -400,6 +401,7 @@ applications that come with the platform <!-- Permission required for CTS test - TrustTestCases --> <permission name="android.permission.PROVIDE_TRUST_AGENT" /> <permission name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> + <permission name="android.permission.TRUST_LISTENER" /> <!-- Permissions required for Incremental CTS tests --> <permission name="com.android.permission.USE_INSTALLER_V2"/> <permission name="android.permission.LOADER_USAGE_STATS"/> diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 373228586161..1629b6ace35d 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -368,7 +368,7 @@ public final class ImageDecoder implements AutoCloseable { * Further, unlike other Sources, this one is not reusable. */ private static class InputStreamSource extends Source { - InputStreamSource(Resources res, InputStream is, int inputDensity) { + InputStreamSource(Resources res, @NonNull InputStream is, int inputDensity) { if (is == null) { throw new IllegalArgumentException("The InputStream cannot be null"); } @@ -1020,7 +1020,7 @@ public final class ImageDecoder implements AutoCloseable { */ @AnyThread @NonNull - public static Source createSource(Resources res, InputStream is) { + public static Source createSource(Resources res, @NonNull InputStream is) { return new InputStreamSource(res, is, Bitmap.getDefaultDensity()); } @@ -1034,7 +1034,7 @@ public final class ImageDecoder implements AutoCloseable { @AnyThread @TestApi @NonNull - public static Source createSource(Resources res, InputStream is, int density) { + public static Source createSource(Resources res, @NonNull InputStream is, int density) { return new InputStreamSource(res, is, density); } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 28b3b04b827d..4972e928dd22 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -288,8 +288,7 @@ public abstract class Drawable { * * @return A copy of the drawable's bounds */ - @NonNull - public final Rect copyBounds() { + public final @NonNull Rect copyBounds() { return new Rect(mBounds); } @@ -308,8 +307,7 @@ public abstract class Drawable { * @see #copyBounds() * @see #copyBounds(android.graphics.Rect) */ - @NonNull - public final Rect getBounds() { + public final @NonNull Rect getBounds() { if (mBounds == ZERO_BOUNDS_RECT) { mBounds = new Rect(); } @@ -327,8 +325,7 @@ public abstract class Drawable { * * @return The dirty bounds of this drawable */ - @NonNull - public Rect getDirtyBounds() { + public @NonNull Rect getDirtyBounds() { return getBounds(); } @@ -457,8 +454,7 @@ public abstract class Drawable { * * @see #setCallback(android.graphics.drawable.Drawable.Callback) */ - @Nullable - public Callback getCallback() { + public @Nullable Callback getCallback() { return mCallback != null ? mCallback.get() : null; } @@ -569,8 +565,7 @@ public abstract class Drawable { * The default return value is 255 if the class does not override this method to return a value * specific to its use of alpha. */ - @IntRange(from=0,to=255) - public int getAlpha() { + public @IntRange(from=0,to=255) int getAlpha() { return 0xFF; } @@ -999,7 +994,8 @@ public abstract class Drawable { * * @see android.graphics.PixelFormat */ - @Deprecated public abstract @PixelFormat.Opacity int getOpacity(); + @Deprecated + public abstract @PixelFormat.Opacity int getOpacity(); /** * Return the appropriate opacity value for two source opacities. If @@ -1059,7 +1055,7 @@ public abstract class Drawable { * if it looks the same and there is no need to redraw it since its * last state. */ - protected boolean onStateChange(int[] state) { + protected boolean onStateChange(@NonNull int[] state) { return false; } @@ -1078,7 +1074,7 @@ public abstract class Drawable { * Override this in your subclass to change appearance if you vary based on * the bounds. */ - protected void onBoundsChange(Rect bounds) { + protected void onBoundsChange(@NonNull Rect bounds) { // Stub method. } @@ -1209,7 +1205,8 @@ public abstract class Drawable { /** * Create a drawable from an inputstream */ - public static Drawable createFromStream(InputStream is, String srcName) { + public static @Nullable Drawable createFromStream(@Nullable InputStream is, + @Nullable String srcName) { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable"); try { return createFromResourceStream(null, null, is, srcName); @@ -1222,8 +1219,8 @@ public abstract class Drawable { * Create a drawable from an inputstream, using the given resources and * value to determine density information. */ - public static Drawable createFromResourceStream(Resources res, TypedValue value, - InputStream is, String srcName) { + public static @Nullable Drawable createFromResourceStream(@Nullable Resources res, + @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName) { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable"); try { return createFromResourceStream(res, value, is, srcName, null); @@ -1238,8 +1235,7 @@ public abstract class Drawable { * * @deprecated Prefer the version without an Options object. */ - @Nullable - public static Drawable createFromResourceStream(@Nullable Resources res, + public static @Nullable Drawable createFromResourceStream(@Nullable Resources res, @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName, @Nullable BitmapFactory.Options opts) { if (is == null) { @@ -1281,7 +1277,8 @@ public abstract class Drawable { return null; } - private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) { + private static Drawable getBitmapDrawable(Resources res, @Nullable TypedValue value, + @NonNull InputStream is) { try { ImageDecoder.Source source = null; if (value != null) { @@ -1369,9 +1366,9 @@ public abstract class Drawable { * a tag in an XML document, tries to create a Drawable from that tag. * Returns null if the tag is not a valid drawable. */ - @NonNull - public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, - @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { + public static @NonNull Drawable createFromXmlInner(@NonNull Resources r, + @NonNull XmlPullParser parser, @NonNull AttributeSet attrs) + throws XmlPullParserException, IOException { return createFromXmlInner(r, parser, attrs, null); } @@ -1381,9 +1378,8 @@ public abstract class Drawable { * document, tries to create a Drawable from that tag. Returns {@code null} * if the tag is not a valid drawable. */ - @NonNull - public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, - @NonNull AttributeSet attrs, @Nullable Theme theme) + public static @NonNull Drawable createFromXmlInner(@NonNull Resources r, + @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { return createFromXmlInnerForDensity(r, parser, attrs, 0, theme); } @@ -1392,8 +1388,7 @@ public abstract class Drawable { * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that * accepts an override density. */ - @NonNull - static Drawable createFromXmlInnerForDensity(@NonNull Resources r, + static @NonNull Drawable createFromXmlInnerForDensity(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, @Nullable Theme theme) throws XmlPullParserException, IOException { return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs, @@ -1403,8 +1398,7 @@ public abstract class Drawable { /** * Create a drawable from file path name. */ - @Nullable - public static Drawable createFromPath(String pathName) { + public static @Nullable Drawable createFromPath(String pathName) { if (pathName == null) { return null; } diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java index 66752a2536d3..8debe26b8c6a 100644 --- a/graphics/java/android/graphics/drawable/DrawableInflater.java +++ b/graphics/java/android/graphics/drawable/DrawableInflater.java @@ -61,8 +61,7 @@ public final class DrawableInflater { * @param id the identifier of the drawable resource * @return a drawable, or {@code null} if the drawable failed to load */ - @Nullable - public static Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) { + public static @Nullable Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) { return loadDrawable(context.getResources(), context.getTheme(), id); } @@ -74,9 +73,8 @@ public final class DrawableInflater { * @param id the identifier of the drawable resource * @return a drawable, or {@code null} if the drawable failed to load */ - @Nullable - public static Drawable loadDrawable( - @NonNull Resources resources, @Nullable Theme theme, @DrawableRes int id) { + public static @Nullable Drawable loadDrawable(@NonNull Resources resources, + @Nullable Theme theme, @DrawableRes int id) { return resources.getDrawable(id, theme); } @@ -111,8 +109,7 @@ public final class DrawableInflater { * @throws XmlPullParserException * @throws IOException */ - @NonNull - public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser, + public @NonNull Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { return inflateFromXmlForDensity(name, parser, attrs, 0, theme); @@ -122,8 +119,7 @@ public final class DrawableInflater { * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts * an override density. */ - @NonNull - Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser, + @NonNull Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, @Nullable Theme theme) throws XmlPullParserException, IOException { // Inner classes must be referenced as Outer$Inner, but XML tag names @@ -146,9 +142,8 @@ public final class DrawableInflater { return drawable; } - @NonNull @SuppressWarnings("deprecation") - private Drawable inflateFromTag(@NonNull String name) { + private @Nullable Drawable inflateFromTag(@NonNull String name) { switch (name) { case "selector": return new StateListDrawable(); @@ -195,8 +190,7 @@ public final class DrawableInflater { } } - @NonNull - private Drawable inflateFromClass(@NonNull String className) { + private @NonNull Drawable inflateFromClass(@NonNull String className) { try { Constructor<? extends Drawable> constructor; synchronized (CONSTRUCTOR_MAP) { diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index ebde75775e84..a63d7f660801 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -352,7 +352,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb } @Override - protected boolean onStateChange(int[] state) { + protected boolean onStateChange(@NonNull int[] state) { if (mDrawable != null && mDrawable.isStateful()) { final boolean changed = mDrawable.setState(state); if (changed) { diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index a03931bfab24..b04b82629b92 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -302,7 +302,7 @@ public final class Icon implements Parcelable { * is available. The {@link android.os.Message#obj obj} * property is populated with the Drawable. */ - public void loadDrawableAsync(Context context, Message andThen) { + public void loadDrawableAsync(@NonNull Context context, @NonNull Message andThen) { if (andThen.getTarget() == null) { throw new IllegalArgumentException("callback message must have a target handler"); } @@ -320,7 +320,7 @@ public final class Icon implements Parcelable { * {@link #loadDrawable(Context)} finished * @param handler {@link Handler} on which to notify the {@code listener} */ - public void loadDrawableAsync(Context context, final OnDrawableLoadedListener listener, + public void loadDrawableAsync(@NonNull Context context, final OnDrawableLoadedListener listener, Handler handler) { new LoadDrawableTask(context, handler, listener).runAsync(); } @@ -335,7 +335,7 @@ public final class Icon implements Parcelable { * to access {@link android.content.res.Resources Resources}, for example. * @return A fresh instance of a drawable for this image, yours to keep. */ - public Drawable loadDrawable(Context context) { + public @Nullable Drawable loadDrawable(Context context) { final Drawable result = loadDrawableInner(context); if (result != null && hasTint()) { result.mutate(); @@ -415,7 +415,7 @@ public final class Icon implements Parcelable { return null; } - private InputStream getUriInputStream(Context context) { + private @Nullable InputStream getUriInputStream(Context context) { final Uri uri = getUri(); final String scheme = uri.getScheme(); if (ContentResolver.SCHEME_CONTENT.equals(scheme) @@ -496,7 +496,7 @@ public final class Icon implements Parcelable { * @param stream The stream on which to serialize the Icon. * @hide */ - public void writeToStream(OutputStream stream) throws IOException { + public void writeToStream(@NonNull OutputStream stream) throws IOException { DataOutputStream dataStream = new DataOutputStream(stream); dataStream.writeInt(VERSION_STREAM_SERIALIZER); @@ -532,7 +532,7 @@ public final class Icon implements Parcelable { * @param stream The input stream from which to reconstruct the Icon. * @hide */ - public static Icon createFromStream(InputStream stream) throws IOException { + public static @Nullable Icon createFromStream(@NonNull InputStream stream) throws IOException { DataInputStream inputStream = new DataInputStream(stream); final int version = inputStream.readInt(); @@ -571,7 +571,7 @@ public final class Icon implements Parcelable { * @return whether this icon is the same as the another one * @hide */ - public boolean sameAs(Icon otherIcon) { + public boolean sameAs(@NonNull Icon otherIcon) { if (otherIcon == this) { return true; } @@ -602,7 +602,7 @@ public final class Icon implements Parcelable { * given resource ID. * @param resId ID of the drawable resource */ - public static Icon createWithResource(Context context, @DrawableRes int resId) { + public static @NonNull Icon createWithResource(Context context, @DrawableRes int resId) { if (context == null) { throw new IllegalArgumentException("Context must not be null."); } @@ -617,7 +617,7 @@ public final class Icon implements Parcelable { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static Icon createWithResource(Resources res, @DrawableRes int resId) { + public static @NonNull Icon createWithResource(Resources res, @DrawableRes int resId) { if (res == null) { throw new IllegalArgumentException("Resource must not be null."); } @@ -632,7 +632,7 @@ public final class Icon implements Parcelable { * @param resPackage Name of the package containing the resource in question * @param resId ID of the drawable resource */ - public static Icon createWithResource(String resPackage, @DrawableRes int resId) { + public static @NonNull Icon createWithResource(String resPackage, @DrawableRes int resId) { if (resPackage == null) { throw new IllegalArgumentException("Resource package name must not be null."); } @@ -646,7 +646,7 @@ public final class Icon implements Parcelable { * Create an Icon pointing to a bitmap in memory. * @param bits A valid {@link android.graphics.Bitmap} object */ - public static Icon createWithBitmap(Bitmap bits) { + public static @NonNull Icon createWithBitmap(Bitmap bits) { if (bits == null) { throw new IllegalArgumentException("Bitmap must not be null."); } @@ -660,7 +660,7 @@ public final class Icon implements Parcelable { * by {@link AdaptiveIconDrawable}. * @param bits A valid {@link android.graphics.Bitmap} object */ - public static Icon createWithAdaptiveBitmap(Bitmap bits) { + public static @NonNull Icon createWithAdaptiveBitmap(Bitmap bits) { if (bits == null) { throw new IllegalArgumentException("Bitmap must not be null."); } @@ -677,7 +677,7 @@ public final class Icon implements Parcelable { * @param offset Offset into <code>data</code> at which the bitmap data starts * @param length Length of the bitmap data */ - public static Icon createWithData(byte[] data, int offset, int length) { + public static @NonNull Icon createWithData(byte[] data, int offset, int length) { if (data == null) { throw new IllegalArgumentException("Data must not be null."); } @@ -693,7 +693,7 @@ public final class Icon implements Parcelable { * * @param uri A uri referring to local content:// or file:// image data. */ - public static Icon createWithContentUri(String uri) { + public static @NonNull Icon createWithContentUri(String uri) { if (uri == null) { throw new IllegalArgumentException("Uri must not be null."); } @@ -707,7 +707,7 @@ public final class Icon implements Parcelable { * * @param uri A uri referring to local content:// or file:// image data. */ - public static Icon createWithContentUri(Uri uri) { + public static @NonNull Icon createWithContentUri(Uri uri) { if (uri == null) { throw new IllegalArgumentException("Uri must not be null."); } @@ -720,8 +720,7 @@ public final class Icon implements Parcelable { * * @param uri A uri referring to local content:// or file:// image data. */ - @NonNull - public static Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) { + public static @NonNull Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) { if (uri == null) { throw new IllegalArgumentException("Uri must not be null."); } @@ -750,7 +749,7 @@ public final class Icon implements Parcelable { * @param tint a color, as in {@link Drawable#setTint(int)} * @return this same object, for use in chained construction */ - public Icon setTint(@ColorInt int tint) { + public @NonNull Icon setTint(@ColorInt int tint) { return setTintList(ColorStateList.valueOf(tint)); } @@ -760,7 +759,7 @@ public final class Icon implements Parcelable { * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint * @return this same object, for use in chained construction */ - public Icon setTintList(ColorStateList tintList) { + public @NonNull Icon setTintList(ColorStateList tintList) { mTintList = tintList; return this; } @@ -809,7 +808,7 @@ public final class Icon implements Parcelable { * @param path A path to a file that contains compressed bitmap data of * a type that {@link android.graphics.BitmapFactory} can decode. */ - public static Icon createWithFilePath(String path) { + public static @NonNull Icon createWithFilePath(String path) { if (path == null) { throw new IllegalArgumentException("Path must not be null."); } 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 index b310dd638e6c..9a6df23ca971 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java @@ -18,9 +18,12 @@ package com.android.wm.shell.back; import android.view.MotionEvent; +import com.android.wm.shell.common.annotations.ExternalThread; + /** - * Interface for SysUI to get access to the Back animation related methods. + * Interface for external process to get access to the Back animation related methods. */ +@ExternalThread public interface BackAnimation { /** @@ -32,4 +35,11 @@ public interface BackAnimation { * Sets whether the back gesture is past the trigger threshold or not. */ void setTriggerBack(boolean triggerBack); + + /** + * Returns a binder that can be passed to an external process to update back animations. + */ + default IBackAnimation createExternalInterface() { + return null; + } } 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 index 229e8ee04982..a5140c3aafff 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -16,6 +16,7 @@ package com.android.wm.shell.back; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; @@ -26,6 +27,7 @@ import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; +import android.content.Context; import android.graphics.Point; import android.graphics.PointF; import android.hardware.HardwareBuffer; @@ -35,16 +37,18 @@ import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceControl; import android.window.BackNavigationInfo; +import android.window.IOnBackInvokedCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.common.RemoteCallable; 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 { +public class BackAnimationController implements RemoteCallable<BackAnimationController> { private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability"; public static final boolean IS_ENABLED = SystemProperties @@ -72,18 +76,26 @@ public class BackAnimationController { private BackNavigationInfo mBackNavigationInfo; private final SurfaceControl.Transaction mTransaction; private final IActivityTaskManager mActivityTaskManager; + private final Context mContext; + @Nullable + private IOnBackInvokedCallback mBackToLauncherCallback; - public BackAnimationController(@ShellMainThread ShellExecutor shellExecutor) { - this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService()); + public BackAnimationController( + @ShellMainThread ShellExecutor shellExecutor, + Context context) { + this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService(), + context); } @VisibleForTesting BackAnimationController(@NonNull ShellExecutor shellExecutor, @NonNull SurfaceControl.Transaction transaction, - @NonNull IActivityTaskManager activityTaskManager) { + @NonNull IActivityTaskManager activityTaskManager, + Context context) { mShellExecutor = shellExecutor; mTransaction = transaction; mActivityTaskManager = activityTaskManager; + mContext = context; } public BackAnimation getBackAnimationImpl() { @@ -92,7 +104,27 @@ public class BackAnimationController { private final BackAnimation mBackAnimation = new BackAnimationImpl(); + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mShellExecutor; + } + private class BackAnimationImpl implements BackAnimation { + private IBackAnimationImpl mBackAnimation; + + @Override + public IBackAnimation createExternalInterface() { + if (mBackAnimation != null) { + mBackAnimation.invalidate(); + } + mBackAnimation = new IBackAnimationImpl(BackAnimationController.this); + return mBackAnimation; + } @Override public void onBackMotion(MotionEvent event) { @@ -105,6 +137,48 @@ public class BackAnimationController { } } + private static class IBackAnimationImpl extends IBackAnimation.Stub { + private BackAnimationController mController; + + IBackAnimationImpl(BackAnimationController controller) { + mController = controller; + } + + @Override + public void setBackToLauncherCallback(IOnBackInvokedCallback callback) { + executeRemoteCallWithTaskPermission(mController, "setBackToLauncherCallback", + (controller) -> mController.setBackToLauncherCallback(callback)); + } + + @Override + public void clearBackToLauncherCallback() { + executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback", + (controller) -> mController.clearBackToLauncherCallback()); + } + + @Override + public void onBackToLauncherAnimationFinished() { + executeRemoteCallWithTaskPermission(mController, "onBackToLauncherAnimationFinished", + (controller) -> mController.onBackToLauncherAnimationFinished()); + } + + void invalidate() { + mController = null; + } + } + + private void setBackToLauncherCallback(IOnBackInvokedCallback callback) { + mBackToLauncherCallback = callback; + } + + private void clearBackToLauncherCallback() { + mBackToLauncherCallback = null; + } + + private void onBackToLauncherAnimationFinished() { + finishAnimation(); + } + /** * Called when a new motion event needs to be transferred to this * {@link BackAnimationController} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl new file mode 100644 index 000000000000..6311f879fd45 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl @@ -0,0 +1,45 @@ +/* + * 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 android.window.IOnBackInvokedCallback; + +/** + * Interface for Launcher process to register back invocation callbacks. + */ +interface IBackAnimation { + + /** + * Sets a {@link IOnBackInvokedCallback} to be invoked when + * back navigation has type {@link BackNavigationInfo#TYPE_RETURN_TO_HOME}. + */ + void setBackToLauncherCallback(in IOnBackInvokedCallback callback); + + /** + * Clears the previously registered {@link IOnBackInvokedCallback}. + */ + void clearBackToLauncherCallback(); + + /** + * Notifies Shell that the back to launcher animation has fully finished + * (including the transition animation that runs after the finger is lifted). + * + * At this point the top window leash (if one was created) should be ready to be released. + * //TODO: Remove once we play the transition animation through shell transitions. + */ + void onBackToLauncherAnimationFinished(); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 8f4cfb0a49a4..4d279bc4e927 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -49,7 +49,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; /** - * Controls to show/update restart-activity buttons on Tasks based on whether the foreground + * Controller to show/update compat UI components on Tasks based on whether the foreground * activities are in compatibility mode. */ public class CompatUIController implements OnDisplaysChangedListener, @@ -228,8 +228,7 @@ public class CompatUIController implements OnDisplaysChangedListener, final CompatUIWindowManager compatUIWindowManager = createLayout(context, taskInfo, taskListener); mActiveLayouts.put(taskInfo.taskId, compatUIWindowManager); - compatUIWindowManager.createLayout(showOnDisplay(taskInfo.displayId), - taskInfo.topActivityInSizeCompat, taskInfo.cameraCompatControlState); + compatUIWindowManager.createLayout(showOnDisplay(taskInfo.displayId), taskInfo); } @VisibleForTesting @@ -254,9 +253,7 @@ public class CompatUIController implements OnDisplaysChangedListener, if (layout == null) { return; } - layout.updateCompatInfo(taskInfo.configuration, taskListener, - showOnDisplay(layout.getDisplayId()), taskInfo.topActivityInSizeCompat, - taskInfo.cameraCompatControlState); + layout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(layout.getDisplayId())); } private void removeLayout(int taskId) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java index 44526b00bf0d..9c001a37e4b6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java @@ -20,28 +20,16 @@ import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.annotation.Nullable; +import android.app.TaskInfo; import android.app.TaskInfo.CameraCompatControlState; import android.content.Context; import android.content.res.Configuration; -import android.graphics.PixelFormat; import android.graphics.Rect; -import android.os.Binder; import android.util.Log; -import android.view.IWindow; import android.view.LayoutInflater; -import android.view.SurfaceControl; -import android.view.SurfaceControlViewHost; -import android.view.SurfaceSession; import android.view.View; -import android.view.WindowManager; -import android.view.WindowlessWindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; @@ -50,26 +38,19 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; /** - * Holds view hierarchy of a root surface and helps to inflate and manage layout for compat - * controls. + * Window manager for the Size Compat restart button and Camera Compat control. */ -class CompatUIWindowManager extends WindowlessWindowManager { +class CompatUIWindowManager extends CompatUIWindowManagerAbstract { - private static final String TAG = "CompatUIWindowManager"; + /** + * The Compat UI should be the topmost child of the Task in case there can be more than one + * child. + */ + private static final int Z_ORDER = Integer.MAX_VALUE; - private final SyncTransactionQueue mSyncQueue; private final CompatUIController.CompatUICallback mCallback; - private final int mDisplayId; - private final int mTaskId; - private final Rect mStableBounds; - private Context mContext; - private Configuration mTaskConfig; - private ShellTaskOrganizer.TaskListener mTaskListener; - private DisplayLayout mDisplayLayout; - - // Remember the last reported states in case visibility changes due to keyguard or - // IME updates. + // Remember the last reported states in case visibility changes due to keyguard or IME updates. @VisibleForTesting boolean mHasSizeCompat; @CameraCompatControlState @@ -82,147 +63,83 @@ class CompatUIWindowManager extends WindowlessWindowManager { @Nullable @VisibleForTesting - CompatUILayout mCompatUILayout; - - @Nullable - private SurfaceControlViewHost mViewHost; - @Nullable - private SurfaceControl mLeash; + CompatUILayout mLayout; CompatUIWindowManager(Context context, Configuration taskConfig, SyncTransactionQueue syncQueue, CompatUIController.CompatUICallback callback, int taskId, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, - boolean hasShownSizeCompatHint, boolean hasShownCameraCompatHint) { - super(taskConfig, null /* rootSurface */, null /* hostInputToken */); - mContext = context; - mSyncQueue = syncQueue; + boolean hasShownSizeCompatHint, boolean hasShownCameraCompatHint) { + super(context, taskConfig, syncQueue, taskId, taskListener, displayLayout); mCallback = callback; - mTaskConfig = taskConfig; - mDisplayId = mContext.getDisplayId(); - mTaskId = taskId; - mTaskListener = taskListener; - mDisplayLayout = displayLayout; mShouldShowSizeCompatHint = !hasShownSizeCompatHint; mShouldShowCameraCompatHint = !hasShownCameraCompatHint; - mStableBounds = new Rect(); - mDisplayLayout.getStableBounds(mStableBounds); } @Override - public void setConfiguration(Configuration configuration) { - super.setConfiguration(configuration); - mContext = mContext.createConfigurationContext(configuration); + protected int getZOrder() { + return Z_ORDER; + } + + + @Override + protected @Nullable View getLayout() { + return mLayout; } @Override - protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) { - // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later. - final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession()) - .setContainerLayer() - .setName("CompatUILeash") - .setHidden(false) - .setCallsite("CompatUIWindowManager#attachToParentSurface"); - attachToParentSurface(builder); - mLeash = builder.build(); - b.setParent(mLeash); + protected void removeLayout() { + mLayout = null; } - /** Creates the layout for compat controls. */ - void createLayout(boolean show, boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState) { - mHasSizeCompat = hasSizeCompat; - mCameraCompatControlState = cameraCompatControlState; - if (!show || mCompatUILayout != null) { - // Wait until compat controls should be visible. - return; - } + @Override + protected boolean eligibleToShowLayout() { + return mHasSizeCompat || shouldShowCameraControl(); + } + + /** + * Updates the internal state with respect to {@code taskInfo} and calls {@link + * #createLayout(boolean)}. + */ + void createLayout(boolean canShow, TaskInfo taskInfo) { + mHasSizeCompat = taskInfo.topActivityInSizeCompat; + mCameraCompatControlState = taskInfo.cameraCompatControlState; + createLayout(canShow); + } + + @Override + protected View createLayout() { + mLayout = inflateLayout(); + mLayout.inject(this); - initCompatUi(); - updateSurfacePosition(); + updateVisibilityOfViews(); - if (hasSizeCompat) { + if (mHasSizeCompat) { mCallback.onSizeCompatRestartButtonAppeared(mTaskId); } + + return mLayout; } - private void createLayout(boolean show) { - createLayout(show, mHasSizeCompat, mCameraCompatControlState); + @VisibleForTesting + CompatUILayout inflateLayout() { + return (CompatUILayout) LayoutInflater.from(mContext).inflate(R.layout.compat_ui_layout, + null); } - /** Called when compat info changed. */ - void updateCompatInfo(Configuration taskConfig, - ShellTaskOrganizer.TaskListener taskListener, boolean show, boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState) { - final Configuration prevTaskConfig = mTaskConfig; - final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener; - mTaskConfig = taskConfig; - mTaskListener = taskListener; + @Override + public void updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, + boolean canShow) { final boolean prevHasSizeCompat = mHasSizeCompat; final int prevCameraCompatControlState = mCameraCompatControlState; - mHasSizeCompat = hasSizeCompat; - mCameraCompatControlState = cameraCompatControlState; + mHasSizeCompat = taskInfo.topActivityInSizeCompat; + mCameraCompatControlState = taskInfo.cameraCompatControlState; - // Update configuration. - mContext = mContext.createConfigurationContext(taskConfig); - setConfiguration(taskConfig); - - if (mCompatUILayout == null || prevTaskListener != taskListener) { - // TaskListener changed, recreate the layout for new surface parent. - release(); - createLayout(show); - return; - } + super.updateCompatInfo(taskInfo, taskListener, canShow); if (prevHasSizeCompat != mHasSizeCompat || prevCameraCompatControlState != mCameraCompatControlState) { updateVisibilityOfViews(); } - - if (!taskConfig.windowConfiguration.getBounds() - .equals(prevTaskConfig.windowConfiguration.getBounds())) { - // Reposition the UI surfaces. - updateSurfacePosition(); - } - - if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) { - // Update layout for RTL. - mCompatUILayout.setLayoutDirection(taskConfig.getLayoutDirection()); - updateSurfacePosition(); - } - - } - - /** Called when the visibility of the UI should change. */ - void updateVisibility(boolean show) { - if (mCompatUILayout == null) { - // Layout may not have been created because it was hidden previously. - createLayout(show); - return; - } - - // Hide compat UIs when IME is showing. - final int newVisibility = show ? View.VISIBLE : View.GONE; - if (mCompatUILayout.getVisibility() != newVisibility) { - mCompatUILayout.setVisibility(newVisibility); - } - } - - /** Called when display layout changed. */ - void updateDisplayLayout(DisplayLayout displayLayout) { - final Rect prevStableBounds = mStableBounds; - final Rect curStableBounds = new Rect(); - displayLayout.getStableBounds(curStableBounds); - mDisplayLayout = displayLayout; - if (!prevStableBounds.equals(curStableBounds)) { - // Stable bounds changed, update UI surface positions. - updateSurfacePosition(); - mStableBounds.set(curStableBounds); - } - } - - /** Called when it is ready to be placed compat UI surface. */ - void attachToParentSurface(SurfaceControl.Builder b) { - mTaskListener.attachChildSurfaceToTask(mTaskId, b); } /** Called when the restart button is clicked. */ @@ -233,7 +150,7 @@ class CompatUIWindowManager extends WindowlessWindowManager { /** Called when the camera treatment button is clicked. */ void onCameraTreatmentButtonClicked() { if (!shouldShowCameraControl()) { - Log.w(TAG, "Camera compat shouldn't receive clicks in the hidden state."); + Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state."); return; } // When a camera control is shown, only two states are allowed: "treament applied" and @@ -244,141 +161,72 @@ class CompatUIWindowManager extends WindowlessWindowManager { ? CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED : CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; mCallback.onCameraControlStateUpdated(mTaskId, mCameraCompatControlState); - mCompatUILayout.updateCameraTreatmentButton(mCameraCompatControlState); + mLayout.updateCameraTreatmentButton(mCameraCompatControlState); } /** Called when the camera dismiss button is clicked. */ void onCameraDismissButtonClicked() { if (!shouldShowCameraControl()) { - Log.w(TAG, "Camera compat shouldn't receive clicks in the hidden state."); + Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state."); return; } mCameraCompatControlState = CAMERA_COMPAT_CONTROL_DISMISSED; mCallback.onCameraControlStateUpdated(mTaskId, CAMERA_COMPAT_CONTROL_DISMISSED); - mCompatUILayout.setCameraControlVisibility(/* show= */ false); + mLayout.setCameraControlVisibility(/* show= */ false); } /** Called when the restart button is long clicked. */ void onRestartButtonLongClicked() { - if (mCompatUILayout == null) { + if (mLayout == null) { return; } - mCompatUILayout.setSizeCompatHintVisibility(/* show= */ true); + mLayout.setSizeCompatHintVisibility(/* show= */ true); } /** Called when either dismiss or treatment camera buttons is long clicked. */ void onCameraButtonLongClicked() { - if (mCompatUILayout == null) { + if (mLayout == null) { return; } - mCompatUILayout.setCameraCompatHintVisibility(/* show= */ true); + mLayout.setCameraCompatHintVisibility(/* show= */ true); } - int getDisplayId() { - return mDisplayId; - } - - int getTaskId() { - return mTaskId; - } - - /** Releases the surface control and tears down the view hierarchy. */ - void release() { - // Hiding before releasing to avoid flickering when transitioning to the Home screen. - mCompatUILayout.setVisibility(View.GONE); - mCompatUILayout = null; - - if (mViewHost != null) { - mViewHost.release(); - mViewHost = null; - } - - if (mLeash != null) { - final SurfaceControl leash = mLeash; - mSyncQueue.runInSync(t -> t.remove(leash)); - mLeash = null; - } - } - - void relayout() { - mViewHost.relayout(getWindowLayoutParams()); - updateSurfacePosition(); - } - - @VisibleForTesting - void updateSurfacePosition() { - if (mCompatUILayout == null || mLeash == null) { + @Override + protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) { + if (mLayout == null) { return; } - - // Use stable bounds to prevent controls from overlapping with system bars. - final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds(); - final Rect stableBounds = new Rect(); - mDisplayLayout.getStableBounds(stableBounds); - stableBounds.intersect(taskBounds); - // Position of the button in the container coordinate. final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? stableBounds.left - taskBounds.left - : stableBounds.right - taskBounds.left - mCompatUILayout.getMeasuredWidth(); + : stableBounds.right - taskBounds.left - mLayout.getMeasuredWidth(); final int positionY = stableBounds.bottom - taskBounds.top - - mCompatUILayout.getMeasuredHeight(); + - mLayout.getMeasuredHeight(); updateSurfacePosition(positionX, positionY); } - private int getLayoutDirection() { - return mContext.getResources().getConfiguration().getLayoutDirection(); - } - - private void updateSurfacePosition(int positionX, int positionY) { - mSyncQueue.runInSync(t -> { - if (mLeash == null || !mLeash.isValid()) { - Log.w(TAG, "The leash has been released."); - return; - } - t.setPosition(mLeash, positionX, positionY); - // The compat UI should be the topmost child of the Task in case there can be more - // than one children. - t.setLayer(mLeash, Integer.MAX_VALUE); - }); - } - - /** Inflates {@link CompatUILayout} on to the root surface. */ - private void initCompatUi() { - if (mViewHost != null) { - throw new IllegalStateException( - "A UI has already been created with this window manager."); - } - - // Construction extracted into the separate methods to allow injection for tests. - mViewHost = createSurfaceViewHost(); - mCompatUILayout = inflateCompatUILayout(); - mCompatUILayout.inject(this); - - updateVisibilityOfViews(); - - mViewHost.setView(mCompatUILayout, getWindowLayoutParams()); - } - private void updateVisibilityOfViews() { + if (mLayout == null) { + return; + } // Size Compat mode restart button. - mCompatUILayout.setRestartButtonVisibility(mHasSizeCompat); + mLayout.setRestartButtonVisibility(mHasSizeCompat); if (mHasSizeCompat && mShouldShowSizeCompatHint) { - mCompatUILayout.setSizeCompatHintVisibility(/* show= */ true); + mLayout.setSizeCompatHintVisibility(/* show= */ true); // Only show by default for the first time. mShouldShowSizeCompatHint = false; } // Camera control for stretched issues. - mCompatUILayout.setCameraControlVisibility(shouldShowCameraControl()); + mLayout.setCameraControlVisibility(shouldShowCameraControl()); if (shouldShowCameraControl() && mShouldShowCameraCompatHint) { - mCompatUILayout.setCameraCompatHintVisibility(/* show= */ true); + mLayout.setCameraCompatHintVisibility(/* show= */ true); // Only show by default for the first time. mShouldShowCameraCompatHint = false; } if (shouldShowCameraControl()) { - mCompatUILayout.updateCameraTreatmentButton(mCameraCompatControlState); + mLayout.updateCameraTreatmentButton(mCameraCompatControlState); } } @@ -386,32 +234,4 @@ class CompatUIWindowManager extends WindowlessWindowManager { return mCameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN && mCameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED; } - - @VisibleForTesting - CompatUILayout inflateCompatUILayout() { - return (CompatUILayout) LayoutInflater.from(mContext) - .inflate(R.layout.compat_ui_layout, null); - } - - @VisibleForTesting - SurfaceControlViewHost createSurfaceViewHost() { - return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); - } - - /** Gets the layout params. */ - private WindowManager.LayoutParams getWindowLayoutParams() { - // Measure how big the hint is since its size depends on the text size. - mCompatUILayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams( - // Cannot be wrap_content as this determines the actual window size - mCompatUILayout.getMeasuredWidth(), mCompatUILayout.getMeasuredHeight(), - TYPE_APPLICATION_OVERLAY, - FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, - PixelFormat.TRANSLUCENT); - winParams.token = new Binder(); - winParams.setTitle(CompatUILayout.class.getSimpleName() + mTaskId); - winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; - return winParams; - } - } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java new file mode 100644 index 000000000000..b9a9db1ee800 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java @@ -0,0 +1,364 @@ +/* + * 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.compatui; + +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import android.annotation.Nullable; +import android.app.TaskInfo; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.os.Binder; +import android.util.Log; +import android.view.IWindow; +import android.view.SurfaceControl; +import android.view.SurfaceControlViewHost; +import android.view.SurfaceSession; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowlessWindowManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.SyncTransactionQueue; + +/** + * A superclass for all Compat UI {@link WindowlessWindowManager}s that holds shared logic and + * exposes general API for {@link CompatUIController}. + * + * <p>Holds view hierarchy of a root surface and helps to inflate and manage layout. + */ +abstract class CompatUIWindowManagerAbstract extends WindowlessWindowManager { + + protected final SyncTransactionQueue mSyncQueue; + protected final int mDisplayId; + protected final int mTaskId; + + protected Context mContext; + protected Configuration mTaskConfig; + protected ShellTaskOrganizer.TaskListener mTaskListener; + protected DisplayLayout mDisplayLayout; + protected final Rect mStableBounds; + + /** + * Utility class for adding and releasing a View hierarchy for this {@link + * WindowlessWindowManager} to {@code mLeash}. + */ + @Nullable + protected SurfaceControlViewHost mViewHost; + + /** + * A surface leash to position the layout relative to the task, since we can't set position for + * the {@code mViewHost} directly. + */ + @Nullable + protected SurfaceControl mLeash; + + protected CompatUIWindowManagerAbstract(Context context, Configuration taskConfig, + SyncTransactionQueue syncQueue, int taskId, + ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout) { + super(taskConfig, null /* rootSurface */, null /* hostInputToken */); + mContext = context; + mSyncQueue = syncQueue; + mTaskConfig = taskConfig; + mDisplayId = mContext.getDisplayId(); + mTaskId = taskId; + mTaskListener = taskListener; + mDisplayLayout = displayLayout; + mStableBounds = new Rect(); + mDisplayLayout.getStableBounds(mStableBounds); + } + + /** + * Returns the z-order of this window which will be passed to the {@link SurfaceControl} once + * {@link #attachToParentSurface} is called. + * + * <p>See {@link SurfaceControl.Transaction#setLayer}. + */ + protected abstract int getZOrder(); + + /** Returns the layout of this window manager. */ + protected abstract @Nullable View getLayout(); + + /** + * Inflates and inits the layout of this window manager on to the root surface if both {@code + * canShow} and {@link #eligibleToShowLayout} are true. + * + * @param canShow whether the layout is allowed to be shown by the parent controller. + */ + void createLayout(boolean canShow) { + if (!canShow || !eligibleToShowLayout() || getLayout() != null) { + // Wait until layout should be visible. + return; + } + + if (mViewHost != null) { + throw new IllegalStateException( + "A UI has already been created with this window manager."); + } + + // Construction extracted into separate methods to allow injection for tests. + mViewHost = createSurfaceViewHost(); + mViewHost.setView(createLayout(), getWindowLayoutParams()); + + updateSurfacePosition(); + } + + /** Inflates and inits the layout of this window manager. */ + protected abstract View createLayout(); + + protected abstract void removeLayout(); + + /** + * Whether the layout is eligible to be shown according to the internal state of the subclass. + * Returns true by default if subclass doesn't override this method. + */ + protected boolean eligibleToShowLayout() { + return true; + } + + @Override + public void setConfiguration(Configuration configuration) { + super.setConfiguration(configuration); + mContext = mContext.createConfigurationContext(configuration); + } + + @Override + protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) { + String className = getClass().getSimpleName(); + final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession()) + .setContainerLayer() + .setName(className + "Leash") + .setHidden(false) + .setCallsite(className + "#attachToParentSurface"); + attachToParentSurface(builder); + mLeash = builder.build(); + b.setParent(mLeash); + + initSurface(mLeash); + } + + /** Inits the z-order of the surface. */ + private void initSurface(SurfaceControl leash) { + final int z = getZOrder(); + mSyncQueue.runInSync(t -> { + if (leash == null || !leash.isValid()) { + Log.w(getTag(), "The leash has been released."); + return; + } + t.setLayer(leash, z); + }); + } + + /** + * Called when compat info changed. + * + * @param canShow whether the layout is allowed to be shown by the parent controller. + */ + void updateCompatInfo(TaskInfo taskInfo, + ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { + final Configuration prevTaskConfig = mTaskConfig; + final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener; + mTaskConfig = taskInfo.configuration; + mTaskListener = taskListener; + + // Update configuration. + setConfiguration(mTaskConfig); + + View layout = getLayout(); + if (layout == null || prevTaskListener != taskListener) { + // TaskListener changed, recreate the layout for new surface parent. + release(); + createLayout(canShow); + return; + } + + boolean boundsUpdated = !mTaskConfig.windowConfiguration.getBounds().equals( + prevTaskConfig.windowConfiguration.getBounds()); + boolean layoutDirectionUpdated = + mTaskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection(); + if (boundsUpdated || layoutDirectionUpdated) { + // Reposition the UI surfaces. + updateSurfacePosition(); + } + + if (layout != null && layoutDirectionUpdated) { + // Update layout for RTL. + layout.setLayoutDirection(mTaskConfig.getLayoutDirection()); + } + } + + + /** + * Updates the visibility of the layout. + * + * @param canShow whether the layout is allowed to be shown by the parent controller. + */ + void updateVisibility(boolean canShow) { + View layout = getLayout(); + if (layout == null) { + // Layout may not have been created because it was hidden previously. + createLayout(canShow); + return; + } + + final int newVisibility = canShow && eligibleToShowLayout() ? View.VISIBLE : View.GONE; + if (layout.getVisibility() != newVisibility) { + layout.setVisibility(newVisibility); + } + } + + /** Called when display layout changed. */ + void updateDisplayLayout(DisplayLayout displayLayout) { + final Rect prevStableBounds = mStableBounds; + final Rect curStableBounds = new Rect(); + displayLayout.getStableBounds(curStableBounds); + mDisplayLayout = displayLayout; + if (!prevStableBounds.equals(curStableBounds)) { + // Stable bounds changed, update UI surface positions. + updateSurfacePosition(); + mStableBounds.set(curStableBounds); + } + } + + /** Called when the surface is ready to be placed under the task surface. */ + @VisibleForTesting + void attachToParentSurface(SurfaceControl.Builder b) { + mTaskListener.attachChildSurfaceToTask(mTaskId, b); + } + + int getDisplayId() { + return mDisplayId; + } + + int getTaskId() { + return mTaskId; + } + + /** Releases the surface control and tears down the view hierarchy. */ + void release() { + // Hiding before releasing to avoid flickering when transitioning to the Home screen. + View layout = getLayout(); + if (layout != null) { + layout.setVisibility(View.GONE); + } + removeLayout(); + + if (mViewHost != null) { + mViewHost.release(); + mViewHost = null; + } + + if (mLeash != null) { + final SurfaceControl leash = mLeash; + mSyncQueue.runInSync(t -> t.remove(leash)); + mLeash = null; + } + } + + /** Re-layouts the view host and updates the surface position. */ + void relayout() { + if (mViewHost == null) { + return; + } + mViewHost.relayout(getWindowLayoutParams()); + updateSurfacePosition(); + } + + /** + * Updates the position of the surface with respect to the task bounds and display layout + * stable bounds. + */ + @VisibleForTesting + void updateSurfacePosition() { + if (mLeash == null) { + return; + } + // Use stable bounds to prevent controls from overlapping with system bars. + final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds(); + final Rect stableBounds = new Rect(); + mDisplayLayout.getStableBounds(stableBounds); + stableBounds.intersect(taskBounds); + + updateSurfacePosition(taskBounds, stableBounds); + } + + /** + * Updates the position of the surface with respect to the given {@code taskBounds} and {@code + * stableBounds}. + */ + protected abstract void updateSurfacePosition(Rect taskBounds, Rect stableBounds); + + /** + * Updates the position of the surface with respect to the given {@code positionX} and {@code + * positionY}. + */ + protected void updateSurfacePosition(int positionX, int positionY) { + mSyncQueue.runInSync(t -> { + if (mLeash == null || !mLeash.isValid()) { + Log.w(getTag(), "The leash has been released."); + return; + } + t.setPosition(mLeash, positionX, positionY); + }); + } + + protected int getLayoutDirection() { + return mContext.getResources().getConfiguration().getLayoutDirection(); + } + + @VisibleForTesting + SurfaceControlViewHost createSurfaceViewHost() { + return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); + } + + /** Gets the layout params. */ + private WindowManager.LayoutParams getWindowLayoutParams() { + View layout = getLayout(); + if (layout == null) { + return new WindowManager.LayoutParams(); + } + // Measure how big the hint is since its size depends on the text size. + layout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + return getWindowLayoutParams(layout.getMeasuredWidth(), layout.getMeasuredHeight()); + } + + /** Gets the layout params given the width and height of the layout. */ + private WindowManager.LayoutParams getWindowLayoutParams(int width, int height) { + final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams( + // Cannot be wrap_content as this determines the actual window size + width, height, + TYPE_APPLICATION_OVERLAY, + FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, + PixelFormat.TRANSLUCENT); + winParams.token = new Binder(); + winParams.setTitle(getClass().getSimpleName() + mTaskId); + winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; + return winParams; + } + + protected final String getTag() { + return getClass().getSimpleName(); + } +} 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 9f4ff7c8dc06..2e54c792ed57 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 @@ -696,11 +696,12 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static Optional<BackAnimationController> provideBackAnimationController( + Context context, @ShellMainThread ShellExecutor shellExecutor ) { if (BackAnimationController.IS_ENABLED) { return Optional.of( - new BackAnimationController(shellExecutor)); + new BackAnimationController(shellExecutor, context)); } return Optional.empty(); } 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 index b738c47ef6ff..21ced0dc5981 100644 --- 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 @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; +import android.content.Context; import android.hardware.HardwareBuffer; import android.os.RemoteCallback; import android.os.RemoteException; @@ -52,6 +53,9 @@ public class BackAnimationControllerTest { private final ShellExecutor mShellExecutor = new TestShellExecutor(); @Mock + private Context mContext; + + @Mock private SurfaceControl.Transaction mTransaction; @Mock @@ -63,7 +67,7 @@ public class BackAnimationControllerTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mController = new BackAnimationController( - mShellExecutor, mTransaction, mActivityTaskManager); + mShellExecutor, mTransaction, mActivityTaskManager, mContext); } private void createNavigationInfo(SurfaceControl topWindowLeash, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index 4352fd3d2c27..741da3fe9f58 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -116,35 +116,17 @@ public class CompatUIControllerTest extends ShellTestCase { TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); - // Verify that the restart button is added with non-null size compat info. + // Verify that the compat controls are added with non-null size compat info. mController.onCompatInfoChanged(taskInfo, mMockTaskListener); verify(mController).createLayout(any(), eq(taskInfo), eq(mMockTaskListener)); - // Verify that the restart button is updated with non-null new size compat info. - mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN), - mMockTaskListener); - - verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener, - true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); - - // Verify that the restart button is updated with new camera state. - mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED), - mMockTaskListener); - - verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener, - true /* show */, true /* hasSizeCompat */, + // Verify that the compat controls are updated with non-null new size compat info. + taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED), - mMockTaskListener); - - verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener, - true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, true /* canShow */); // Verify that compat controls are removed with null compat info. mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, @@ -155,7 +137,7 @@ public class CompatUIControllerTest extends ShellTestCase { clearInvocations(mMockLayout); clearInvocations(mController); - // Verify that compat controls are removed with dismissed camera state. + // Verify that compat controls are removed with no size compat and dismissed camera state. taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); @@ -245,11 +227,11 @@ public class CompatUIControllerTest extends ShellTestCase { verify(mMockLayout).updateVisibility(false); // Verify button remains hidden while IME is showing. - mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN); + mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener, - false /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, false /* canShow */); // Verify button is shown after IME is hidden. mController.onImeVisibilityChanged(DISPLAY_ID, false /* isShowing */); @@ -268,11 +250,11 @@ public class CompatUIControllerTest extends ShellTestCase { verify(mMockLayout).updateVisibility(false); // Verify button remains hidden while keyguard is occluded. - mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN); + mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener, - false /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, false /* canShow */); // Verify button is shown after keyguard becomes not occluded. mController.onKeyguardOccludedChanged(false); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java index 353d8fe8bc52..211781798af7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java @@ -27,6 +27,9 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import android.app.ActivityManager; +import android.app.TaskInfo; +import android.app.TaskInfo.CameraCompatControlState; import android.content.res.Configuration; import android.testing.AndroidTestingRunner; import android.view.LayoutInflater; @@ -83,7 +86,7 @@ public class CompatUILayoutTest extends ShellTestCase { spyOn(mWindowManager); spyOn(mCompatUILayout); doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost(); - doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout(); + doReturn(mCompatUILayout).when(mWindowManager).inflateLayout(); } @Test @@ -107,8 +110,8 @@ public class CompatUILayoutTest extends ShellTestCase { @Test public void testOnClickForSizeCompatHint() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); final LinearLayout sizeCompatHint = mCompatUILayout.findViewById(R.id.size_compat_hint); sizeCompatHint.performClick(); @@ -117,8 +120,8 @@ public class CompatUILayoutTest extends ShellTestCase { @Test public void testUpdateCameraTreatmentButton_treatmentAppliedByDefault() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED)); final ImageButton button = mCompatUILayout.findViewById(R.id.camera_compat_treatment_button); button.performClick(); @@ -135,8 +138,8 @@ public class CompatUILayoutTest extends ShellTestCase { @Test public void testUpdateCameraTreatmentButton_treatmentSuggestedByDefault() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); final ImageButton button = mCompatUILayout.findViewById(R.id.camera_compat_treatment_button); button.performClick(); @@ -153,8 +156,8 @@ public class CompatUILayoutTest extends ShellTestCase { @Test public void testOnCameraDismissButtonClicked() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); final ImageButton button = mCompatUILayout.findViewById(R.id.camera_compat_dismiss_button); button.performClick(); @@ -188,11 +191,19 @@ public class CompatUILayoutTest extends ShellTestCase { @Test public void testOnClickForCameraCompatHint() { - mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* show */, createTaskInfo(false /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); final LinearLayout hint = mCompatUILayout.findViewById(R.id.camera_compat_hint); hint.performClick(); verify(mCompatUILayout).setCameraCompatHintVisibility(/* show= */ false); } + + private static TaskInfo createTaskInfo(boolean hasSizeCompat, + @CameraCompatControlState int cameraCompatControlState) { + ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); + taskInfo.topActivityInSizeCompat = hasSizeCompat; + taskInfo.cameraCompatControlState = cameraCompatControlState; + return taskInfo; + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java index 11c797363819..de882eae1503 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java @@ -26,8 +26,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -35,6 +35,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.app.ActivityManager; +import android.app.TaskInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.testing.AndroidTestingRunner; @@ -75,47 +77,45 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private CompatUILayout mCompatUILayout; @Mock private SurfaceControlViewHost mViewHost; - private Configuration mTaskConfig; private CompatUIWindowManager mWindowManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTaskConfig = new Configuration(); mWindowManager = new CompatUIWindowManager(mContext, new Configuration(), mSyncTransactionQueue, mCallback, TASK_ID, mTaskListener, new DisplayLayout(), false /* hasShownSizeCompatHint */, false /* hasShownSizeCompatHint */); spyOn(mWindowManager); - doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout(); + doReturn(mCompatUILayout).when(mWindowManager).inflateLayout(); doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost(); } @Test public void testCreateSizeCompatButton() { // Not create layout if show is false. - mWindowManager.createLayout(false /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(false /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); - verify(mWindowManager, never()).inflateCompatUILayout(); + verify(mWindowManager, never()).inflateLayout(); // Not create hint popup. mWindowManager.mShouldShowSizeCompatHint = false; - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); - verify(mWindowManager).inflateCompatUILayout(); + verify(mWindowManager).inflateLayout(); verify(mCompatUILayout, never()).setSizeCompatHintVisibility(true /* show */); // Create hint popup. mWindowManager.release(); mWindowManager.mShouldShowSizeCompatHint = true; - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); - verify(mWindowManager, times(2)).inflateCompatUILayout(); + verify(mWindowManager, times(2)).inflateLayout(); assertNotNull(mCompatUILayout); verify(mCompatUILayout).setSizeCompatHintVisibility(true /* show */); assertFalse(mWindowManager.mShouldShowSizeCompatHint); @@ -123,10 +123,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testRelease() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); - verify(mWindowManager).inflateCompatUILayout(); + verify(mWindowManager).inflateLayout(); mWindowManager.release(); @@ -135,65 +135,104 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testUpdateCompatInfo() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* canShow */, taskInfo); // No diff clearInvocations(mWindowManager); - mWindowManager.updateCompatInfo(mTaskConfig, mTaskListener, true /* show */, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */); verify(mWindowManager, never()).updateSurfacePosition(); verify(mWindowManager, never()).release(); - verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt()); + verify(mWindowManager, never()).createLayout(anyBoolean()); // Change task listener, recreate button. clearInvocations(mWindowManager); final ShellTaskOrganizer.TaskListener newTaskListener = mock( ShellTaskOrganizer.TaskListener.class); - mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, - true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); verify(mWindowManager).release(); - verify(mWindowManager).createLayout(anyBoolean(), anyBoolean(), anyInt()); + verify(mWindowManager).createLayout(true); + + // Change in Size Compat to false, hides restart button. + clearInvocations(mWindowManager); + taskInfo = createTaskInfo(false /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); + + verify(mCompatUILayout).setRestartButtonVisibility(/* show */ false); + + // Change in Size Compat to true, shows restart button. + clearInvocations(mWindowManager); + clearInvocations(mCompatUILayout); + taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); + + verify(mCompatUILayout).setRestartButtonVisibility(/* show */ true); // Change Camera Compat state, show a control. - mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, true /* show */, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + clearInvocations(mWindowManager); + clearInvocations(mCompatUILayout); + taskInfo = createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); verify(mCompatUILayout).setCameraControlVisibility(/* show */ true); verify(mCompatUILayout).updateCameraTreatmentButton( CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + // Change Camera Compat state, update a control. clearInvocations(mWindowManager); clearInvocations(mCompatUILayout); - // Change Camera Compat state, update a control. - mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, true /* show */, - true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + taskInfo = createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); verify(mCompatUILayout).setCameraControlVisibility(/* show */ true); verify(mCompatUILayout).updateCameraTreatmentButton( CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + // Change Camera Compat state to hidden, hide a control. clearInvocations(mWindowManager); clearInvocations(mCompatUILayout); - // Change Camera Compat state to hidden, hide a control. - mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, - true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); verify(mCompatUILayout).setCameraControlVisibility(/* show */ false); // Change task bounds, update position. clearInvocations(mWindowManager); - final Configuration newTaskConfiguration = new Configuration(); - newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000)); - mWindowManager.updateCompatInfo(newTaskConfiguration, newTaskListener, - true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000)); + mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */); verify(mWindowManager).updateSurfacePosition(); } @Test + public void testUpdateCompatInfoLayoutNotInflatedYet() { + TaskInfo taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(false /* canShow */, taskInfo); + + verify(mWindowManager, never()).inflateLayout(); + + // Change topActivityInSizeCompat to false and pass canShow true, layout shouldn't be + // inflated + clearInvocations(mWindowManager); + taskInfo = createTaskInfo(false /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */); + + verify(mWindowManager, never()).inflateLayout(); + + // Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated. + clearInvocations(mWindowManager); + taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */); + + verify(mWindowManager).inflateLayout(); + } + + @Test public void testUpdateDisplayLayout() { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.logicalWidth = 1000; @@ -237,26 +276,25 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testUpdateVisibility() { // Create button if it is not created. - mWindowManager.mCompatUILayout = null; + mWindowManager.mLayout = null; mWindowManager.mHasSizeCompat = true; - mWindowManager.updateVisibility(true /* show */); + mWindowManager.updateVisibility(true /* canShow */); - verify(mWindowManager).createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + verify(mWindowManager).createLayout(true /* canShow */); // Hide button. clearInvocations(mWindowManager); doReturn(View.VISIBLE).when(mCompatUILayout).getVisibility(); - mWindowManager.updateVisibility(false /* show */); + mWindowManager.updateVisibility(false /* canShow */); - verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt()); + verify(mWindowManager, never()).createLayout(anyBoolean(), any()); verify(mCompatUILayout).setVisibility(View.GONE); // Show button. doReturn(View.GONE).when(mCompatUILayout).getVisibility(); - mWindowManager.updateVisibility(true /* show */); + mWindowManager.updateVisibility(true /* canShow */); - verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt()); + verify(mWindowManager, never()).createLayout(anyBoolean(), any()); verify(mCompatUILayout).setVisibility(View.VISIBLE); } @@ -270,8 +308,8 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testOnCameraDismissButtonClicked() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); clearInvocations(mCompatUILayout); mWindowManager.onCameraDismissButtonClicked(); @@ -281,8 +319,8 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testOnCameraTreatmentButtonClicked() { - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); clearInvocations(mCompatUILayout); mWindowManager.onCameraTreatmentButtonClicked(); @@ -310,10 +348,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase { public void testOnRestartButtonLongClicked_showHint() { // Not create hint popup. mWindowManager.mShouldShowSizeCompatHint = false; - mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_HIDDEN); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_HIDDEN)); - verify(mWindowManager).inflateCompatUILayout(); + verify(mWindowManager).inflateLayout(); verify(mCompatUILayout, never()).setSizeCompatHintVisibility(true /* show */); mWindowManager.onRestartButtonLongClicked(); @@ -325,10 +363,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase { public void testOnCamerControlLongClicked_showHint() { // Not create hint popup. mWindowManager.mShouldShowCameraCompatHint = false; - mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); - verify(mWindowManager).inflateCompatUILayout(); + verify(mWindowManager).inflateLayout(); verify(mCompatUILayout, never()).setCameraCompatHintVisibility(true /* show */); mWindowManager.onCameraButtonLongClicked(); @@ -339,30 +377,37 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test public void testCreateCameraCompatControl() { // Not create layout if show is false. - mWindowManager.createLayout(false /* show */, false /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(false /* canShow */, createTaskInfo(false /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); - verify(mWindowManager, never()).inflateCompatUILayout(); + verify(mWindowManager, never()).inflateLayout(); // Not create hint popup. mWindowManager.mShouldShowCameraCompatHint = false; - mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); - verify(mWindowManager).inflateCompatUILayout(); + verify(mWindowManager).inflateLayout(); verify(mCompatUILayout, never()).setCameraCompatHintVisibility(true /* show */); verify(mCompatUILayout).setCameraControlVisibility(true /* show */); // Create hint popup. mWindowManager.release(); mWindowManager.mShouldShowCameraCompatHint = true; - mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); + mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */, + CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED)); - verify(mWindowManager, times(2)).inflateCompatUILayout(); + verify(mWindowManager, times(2)).inflateLayout(); assertNotNull(mCompatUILayout); verify(mCompatUILayout, times(2)).setCameraControlVisibility(true /* show */); assertFalse(mWindowManager.mShouldShowCameraCompatHint); } + private static TaskInfo createTaskInfo(boolean hasSizeCompat, + @TaskInfo.CameraCompatControlState int cameraCompatControlState) { + ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); + taskInfo.topActivityInSizeCompat = hasSizeCompat; + taskInfo.cameraCompatControlState = cameraCompatControlState; + return taskInfo; + } } diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index 5f02a430f384..e2e48d35a672 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -43,7 +43,6 @@ import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.StampedLock; /** * <p>The ImageReader class allows direct application access to image data @@ -676,8 +675,7 @@ public class ImageReader implements AutoCloseable { * If no handler specified and the calling thread has no looper. */ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) { - long writeStamp = mListenerLock.writeLock(); - try { + synchronized (mListenerLock) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper == null) { @@ -693,8 +691,6 @@ public class ImageReader implements AutoCloseable { mListenerExecutor = null; } mListener = listener; - } finally { - mListenerLock.unlockWrite(writeStamp); } } @@ -717,12 +713,9 @@ public class ImageReader implements AutoCloseable { throw new IllegalArgumentException("executor must not be null"); } - long writeStamp = mListenerLock.writeLock(); - try { + synchronized (mListenerLock) { mListenerExecutor = executor; mListener = listener; - } finally { - mListenerLock.unlockWrite(writeStamp); } } @@ -738,8 +731,6 @@ public class ImageReader implements AutoCloseable { /** * Callback that is called when a new image is available from ImageReader. * - * This callback must not modify or close the passed {@code reader}. - * * @param reader the ImageReader the callback is associated with. * @see ImageReader * @see Image @@ -898,41 +889,28 @@ public class ImageReader implements AutoCloseable { return; } - synchronized (ir.mCloseLock) { - if (!ir.mIsReaderValid) { - // It's dangerous to fire onImageAvailable() callback when the ImageReader - // is being closed, as application could acquire next image in the - // onImageAvailable() callback. - return; - } - } - final Executor executor; - final long readStamp = ir.mListenerLock.readLock(); - try { + final OnImageAvailableListener listener; + synchronized (ir.mListenerLock) { executor = ir.mListenerExecutor; - if (executor == null) { - return; - } - } finally { - ir.mListenerLock.unlockRead(readStamp); + listener = ir.mListener; + } + final boolean isReaderValid; + synchronized (ir.mCloseLock) { + isReaderValid = ir.mIsReaderValid; } - executor.execute(() -> { - // Acquire readlock to ensure that the ImageReader does not change its - // state while a listener is actively processing. - final long rStamp = ir.mListenerLock.readLock(); - try { - // Fire onImageAvailable of the latest non-null listener - // This ensures that if the listener changes while messages are in queue, the - // in-flight messages will call onImageAvailable of the new listener instead - if (ir.mListener != null) { - ir.mListener.onImageAvailable(ir); + // It's dangerous to fire onImageAvailable() callback when the ImageReader + // is being closed, as application could acquire next image in the + // onImageAvailable() callback. + if (executor != null && listener != null && isReaderValid) { + executor.execute(new Runnable() { + @Override + public void run() { + listener.onImageAvailable(ir); } - } finally { - ir.mListenerLock.unlockRead(rStamp); - } - }); + }); + } } /** @@ -1092,7 +1070,7 @@ public class ImageReader implements AutoCloseable { private Surface mSurface; private int mEstimatedNativeAllocBytes; - private final StampedLock mListenerLock = new StampedLock(); + private final Object mListenerLock = new Object(); private final Object mCloseLock = new Object(); private boolean mIsReaderValid = false; private OnImageAvailableListener mListener; diff --git a/media/java/android/media/tv/BroadcastInfoRequest.java b/media/java/android/media/tv/BroadcastInfoRequest.java index f7a52f22e93a..cbd8c1fd53cd 100644 --- a/media/java/android/media/tv/BroadcastInfoRequest.java +++ b/media/java/android/media/tv/BroadcastInfoRequest.java @@ -56,6 +56,8 @@ public abstract class BroadcastInfoRequest implements Parcelable { switch (type) { case TvInputManager.BROADCAST_INFO_TYPE_TS: return TsRequest.createFromParcelBody(source); + case TvInputManager.BROADCAST_INFO_TYPE_TABLE: + return TableRequest.createFromParcelBody(source); case TvInputManager.BROADCAST_INFO_TYPE_SECTION: return SectionRequest.createFromParcelBody(source); case TvInputManager.BROADCAST_INFO_TYPE_PES: diff --git a/media/java/android/media/tv/BroadcastInfoResponse.java b/media/java/android/media/tv/BroadcastInfoResponse.java index ff4ec15bca5b..4ba2b2c2ff7b 100644 --- a/media/java/android/media/tv/BroadcastInfoResponse.java +++ b/media/java/android/media/tv/BroadcastInfoResponse.java @@ -57,6 +57,8 @@ public abstract class BroadcastInfoResponse implements Parcelable { switch (type) { case TvInputManager.BROADCAST_INFO_TYPE_TS: return TsResponse.createFromParcelBody(source); + case TvInputManager.BROADCAST_INFO_TYPE_TABLE: + return TableResponse.createFromParcelBody(source); case TvInputManager.BROADCAST_INFO_TYPE_SECTION: return SectionResponse.createFromParcelBody(source); case TvInputManager.BROADCAST_INFO_TYPE_PES: diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 6329565ca567..66527802a0e4 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -158,7 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], } @@ -167,6 +166,7 @@ filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ ":framework-connectivity-ipsec-sources", + ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], @@ -194,15 +194,12 @@ cc_library_shared { "jni/onload.cpp", ], shared_libs: [ + "libandroid", "liblog", - ], - static_libs: [ - "libnativehelper_compat_libc++", + "libnativehelper", ], stl: "none", apex_available: [ "com.android.tethering", - // TODO: remove when ConnectivityT moves to APEX. - "//apex_available:platform", ], } diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java index 5ce7e59b38ff..0414bb79f83b 100644 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; @@ -192,9 +191,13 @@ public class NetworkStatsManager { } } - /** @hide */ + /** + * Set poll force flag to indicate that calling any subsequent query method will force a stats + * poll. + * @hide + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setPollForce(boolean pollForce) { if (pollForce) { mFlags |= FLAG_POLL_FORCE; diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 577ac5466692..9bffbfb27a8d 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SystemApi; import android.app.SystemServiceRegistry; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -57,5 +58,15 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new IpSecManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.NETWORK_STATS_SERVICE, + NetworkStatsManager.class, + (context, serviceBinder) -> { + INetworkStatsService service = + INetworkStatsService.Stub.asInterface(serviceBinder); + return new NetworkStatsManager(context, service); + } + ); } } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java index 56faa52e82df..4ebaf2b8cdb8 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java @@ -184,14 +184,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE, mType); + proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); + proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); proto.end(start); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java index dfa347f6f12b..2236d70c3502 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java @@ -212,7 +212,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); } proto.end(start); diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java index 735c44d5c87e..67d48f0000d5 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); + proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); proto.end(startStats); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java index 78c137073aaa..822a16e0bb41 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,17 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); + + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + bucketStart[i]); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); proto.end(startBucket); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java index 9b58b016bbf3..7b5afd720016 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java @@ -79,7 +79,8 @@ public final class NetworkTemplate implements Parcelable { MATCH_WIFI, MATCH_ETHERNET, MATCH_BLUETOOTH, - MATCH_CARRIER + MATCH_PROXY, + MATCH_CARRIER, }) public @interface TemplateMatchRule{} @@ -104,9 +105,8 @@ public final class NetworkTemplate implements Parcelable { /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; /** - * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. - * - * @hide + * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy + * network type. */ public static final int MATCH_PROXY = 9; /** diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp index d2d6ef0cbbb1..5100e7c5b9a4 100644 --- a/packages/ConnectivityT/service/Android.bp +++ b/packages/ConnectivityT/service/Android.bp @@ -28,6 +28,11 @@ filegroup { "src/com/android/server/net/NetworkStats*.java", "src/com/android/server/net/BpfInterfaceMapUpdater.java", "src/com/android/server/net/InterfaceMapValue.java", + "src/com/android/server/net/CookieTagMapKey.java", + "src/com/android/server/net/CookieTagMapValue.java", + "src/com/android/server/net/StatsMapKey.java", + "src/com/android/server/net/StatsMapValue.java", + "src/com/android/server/net/UidStatsMapKey.java", ], path: "src", visibility: [ @@ -35,6 +40,30 @@ filegroup { ], } +// For test code only. +filegroup { + name: "lib_networkStatsFactory_native", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + +filegroup { + name: "services.connectivity-netstats-jni-sources", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + "jni/com_android_server_net_NetworkStatsService.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + // Nsd related libraries. filegroup { @@ -83,7 +112,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-netstats-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], @@ -93,6 +121,7 @@ filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ ":services.connectivity-ipsec-sources", + ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp index 8b6526ff49f0..8b6526ff49f0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp index f8a81682bdcf..f8a81682bdcf 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java new file mode 100644 index 000000000000..443e5b38475e --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java @@ -0,0 +1,33 @@ +/* + * 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.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for cookie tag map. + */ +public class CookieTagMapKey extends Struct { + @Field(order = 0, type = Type.S64) + public final long socketCookie; + + public CookieTagMapKey(final long socketCookie) { + this.socketCookie = socketCookie; + } +} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java new file mode 100644 index 000000000000..93b9195f92da --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java @@ -0,0 +1,37 @@ +/* + * 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.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Value for cookie tag map. + */ +public class CookieTagMapValue extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + public CookieTagMapValue(final long uid, final long tag) { + this.uid = uid; + this.tag = tag; + } +} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java index 668d1cba921b..151c90dd4155 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java @@ -54,6 +54,10 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ public class NetworkStatsFactory { + static { + System.loadLibrary("service-connectivity"); + } + private static final String TAG = "NetworkStatsFactory"; private static final boolean USE_NATIVE_PARSING = true; diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java index c371f0859aa1..a006cd597568 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,9 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + mPending.getTotalBytes()); } - getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + getOrLoadCompleteLocked().dumpDebug(proto, + NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); proto.end(start); } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java index 9f3371b724cf..7a5ba09f27f9 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java @@ -62,6 +62,7 @@ import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -102,6 +103,7 @@ import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -169,7 +171,12 @@ import java.util.concurrent.TimeUnit; * Collect and persist detailed network statistics, and provide this data to * other system services. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { + static { + System.loadLibrary("service-connectivity"); + } + static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); @@ -2004,12 +2011,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + mActiveUidIfaces); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mUidTagRecorder.dumpDebugLocked(proto, + NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); proto.flush(); } @@ -2019,8 +2029,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); + proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); proto.end(start); } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 5bba0b17aa42..65ccd2007299 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -23,7 +23,9 @@ import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NS import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; @@ -43,6 +45,7 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java new file mode 100644 index 000000000000..ea8d83638347 --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java @@ -0,0 +1,46 @@ +/* + * 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.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for both stats maps. + */ +public class StatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + @Field(order = 2, type = Type.U32) + public final long counterSet; + + @Field(order = 3, type = Type.U32) + public final long ifaceIndex; + + public StatsMapKey(final long uid, final long tag, final long counterSet, + final long ifaceIndex) { + this.uid = uid; + this.tag = tag; + this.counterSet = counterSet; + this.ifaceIndex = ifaceIndex; + } +} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java new file mode 100644 index 000000000000..48f26ce686e2 --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java @@ -0,0 +1,46 @@ +/* + * 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.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Value used for both stats maps and uid stats map. + */ +public class StatsMapValue extends Struct { + @Field(order = 0, type = Type.U63) + public final long rxPackets; + + @Field(order = 1, type = Type.U63) + public final long rxBytes; + + @Field(order = 2, type = Type.U63) + public final long txPackets; + + @Field(order = 3, type = Type.U63) + public final long txBytes; + + public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets, + final long txBytes) { + this.rxPackets = rxPackets; + this.rxBytes = rxBytes; + this.txPackets = txPackets; + this.txBytes = txBytes; + } +} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java new file mode 100644 index 000000000000..2849f94c9383 --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java @@ -0,0 +1,33 @@ +/* + * 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.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for uid stats map. + */ +public class UidStatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + public UidStatsMapKey(final long uid) { + this.uid = uid; + } +} diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml index c8ddcc870e46..6940c39d6617 100644 --- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml +++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml @@ -27,14 +27,14 @@ android:layout_gravity="center"> <ImageView android:id="@+id/user_photo" - android:layout_width="@dimen/user_photo_size_in_profile_info_dialog" - android:layout_height="@dimen/user_photo_size_in_profile_info_dialog" + android:layout_width="@dimen/user_photo_size_in_user_info_dialog" + android:layout_height="@dimen/user_photo_size_in_user_info_dialog" android:contentDescription="@string/user_image_photo_selector" android:scaleType="fitCenter"/> <ImageView android:id="@+id/add_a_photo_icon" - android:layout_width="@dimen/add_a_photo_icon_size_in_profile_info_dialog" - android:layout_height="@dimen/add_a_photo_icon_size_in_profile_info_dialog" + android:layout_width="@dimen/add_a_photo_icon_size_in_user_info_dialog" + android:layout_height="@dimen/add_a_photo_icon_size_in_user_info_dialog" android:src="@drawable/add_a_photo_circled" android:layout_gravity="bottom|right" /> </FrameLayout> @@ -42,7 +42,7 @@ <EditText android:id="@+id/user_name" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="@dimen/user_name_height_in_user_info_dialog" android:layout_gravity="center" android:minWidth="200dp" android:layout_marginStart="6dp" diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml index 120df76218b3..e1bd9f705577 100644 --- a/packages/SettingsLib/res/values/dimens.xml +++ b/packages/SettingsLib/res/values/dimens.xml @@ -99,8 +99,9 @@ <dimen name="update_user_photo_popup_min_width">300dp</dimen> <dimen name="add_a_photo_circled_padding">6dp</dimen> - <dimen name="user_photo_size_in_profile_info_dialog">112dp</dimen> - <dimen name="add_a_photo_icon_size_in_profile_info_dialog">32dp</dimen> + <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen> + <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen> + <dimen name="user_name_height_in_user_info_dialog">48sp</dimen> <integer name="avatar_picker_columns">3</integer> <dimen name="avatar_size_in_picker">96dp</dimen> diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java index b0a647e0dd2f..95f7ef41b10b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java @@ -81,8 +81,8 @@ public class DataUsageUtilsTest { when(mSubscriptionManager.isActiveSubscriptionId(SUB_ID)).thenReturn(false); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse(); } @Test @@ -94,8 +94,8 @@ public class DataUsageUtilsTest { .thenReturn(new String[] {SUBSCRIBER_ID}); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse(); } @Test @@ -107,7 +107,7 @@ public class DataUsageUtilsTest { .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2}); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isTrue(); } } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 00b5f5019485..a6bfc408be7e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -84,6 +84,7 @@ public class SystemSettings { Settings.System.RING_VIBRATION_INTENSITY, Settings.System.HAPTIC_FEEDBACK_INTENSITY, Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, + Settings.System.HAPTIC_FEEDBACK_ENABLED, Settings.System.DISPLAY_COLOR_MODE_VENDOR_HINT, // must precede DISPLAY_COLOR_MODE Settings.System.DISPLAY_COLOR_MODE, Settings.System.ALARM_ALERT, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 246466e16c74..bbfab0bfa792 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -314,6 +314,7 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.USER_PREFERRED_RESOLUTION_HEIGHT, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Global.USER_PREFERRED_RESOLUTION_WIDTH, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Global.Wearable.WET_MODE_ON, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index 6bcb7695cd22..06712cc68b89 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -124,6 +124,7 @@ public class SystemSettingsValidators { VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); VALIDATORS.put(System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); + VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(System.RINGTONE, URI_VALIDATOR); VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR); VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 13ae87015fa4..3de1fb2b4ba4 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -659,7 +659,8 @@ public class SettingsBackupTest { Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY, Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED, Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER, - Settings.Global.Wearable.WET_MODE_ON); + Settings.Global.Wearable.WET_MODE_ON, + Settings.Global.Wearable.COOLDOWN_MODE_ON); private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS = newHashSet( diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 6f4cd4a0f6ee..ef5849c73b72 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -562,12 +562,14 @@ <!-- 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" /> + <uses-permission android:name="android.permission.TRUST_LISTENER" /> <!-- Permission required for CTS test - CtsGameManagerTestCases --> <uses-permission android:name="android.permission.MANAGE_GAME_MODE" /> <!-- Permission required for CTS test - CtsGameServiceTestCases --> <uses-permission android:name="android.permission.SET_GAME_SERVICE" /> + <uses-permission android:name="android.permission.MANAGE_GAME_ACTIVITY" /> <!-- Permission required for CTS test - ClipboardManagerTest --> <uses-permission android:name="android.permission.SET_CLIP_SOURCE" /> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 776a5117cb2e..c9bd3710ca79 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -39,6 +39,7 @@ <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.INJECT_EVENTS" /> + <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" /> <uses-permission android:name="android.permission.DUMP" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml index 51d160892a01..978998d6ca2c 100644 --- a/packages/SystemUI/res/layout/media_session_view.xml +++ b/packages/SystemUI/res/layout/media_session_view.xml @@ -29,14 +29,14 @@ android:theme="@style/MediaPlayer"> <ImageView + android:id="@+id/album_art" android:layout_width="match_parent" - android:layout_height="184dp" + android:layout_height="@dimen/qs_media_session_height_expanded" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:translationZ="0dp" - android:id="@+id/album_art" android:scaleType="centerCrop" android:adjustViewBounds="true" android:clipToOutline="true" @@ -154,10 +154,7 @@ android:layout_marginStart="@dimen/qs_media_padding" android:layout_marginEnd="@dimen/qs_media_padding" android:layout_marginTop="0dp" - android:layout_marginBottom="0dp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/media_seamless" - app:layout_constraintBottom_toTopOf="@id/actionEnd" /> + android:layout_marginBottom="0dp" /> <ImageButton android:id="@+id/actionPrev" @@ -168,11 +165,8 @@ android:layout_marginEnd="0dp" android:layout_marginBottom="0dp" android:layout_marginTop="0dp" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_progress_bar" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + app:layout_constraintHorizontal_bias="1" + app:layout_constraintHorizontal_chainStyle="packed" /> <!-- Seek Bar --> <!-- As per Material Design on Bidirectionality, this is forced to LTR in code --> @@ -188,11 +182,7 @@ android:layout_marginBottom="0dp" android:layout_marginTop="0dp" android:layout_marginStart="0dp" - android:layout_marginEnd="0dp" - app:layout_constraintStart_toEndOf="@id/actionPrev" - app:layout_constraintEnd_toStartOf="@id/actionNext" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + android:layout_marginEnd="0dp" /> <ImageButton android:id="@+id/actionNext" @@ -202,11 +192,7 @@ android:layout_marginStart="0dp" android:layout_marginEnd="@dimen/qs_media_action_spacing" android:layout_marginBottom="0dp" - android:layout_marginTop="0dp" - app:layout_constraintStart_toEndOf="@id/media_progress_bar" - app:layout_constraintEnd_toStartOf="@id/actionStart" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + android:layout_marginTop="0dp" /> <ImageButton android:id="@+id/actionStart" @@ -216,11 +202,7 @@ android:layout_marginStart="@dimen/qs_media_action_spacing" android:layout_marginEnd="@dimen/qs_media_action_spacing" android:layout_marginBottom="0dp" - android:layout_marginTop="0dp" - app:layout_constraintStart_toEndOf="@id/actionNext" - app:layout_constraintEnd_toStartOf="@id/actionEnd" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + android:layout_marginTop="0dp" /> <ImageButton android:id="@+id/actionEnd" @@ -231,11 +213,7 @@ android:layout_marginEnd="4dp" android:layout_marginBottom="0dp" android:layout_marginTop="0dp" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintStart_toEndOf="@id/actionStart" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + app:layout_constraintHorizontal_chainStyle="packed" /> <!-- Long press menu --> <TextView diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml index 536b0423ce16..02c58e468c30 100644 --- a/packages/SystemUI/res/layout/qs_tile_label.xml +++ b/packages/SystemUI/res/layout/qs_tile_label.xml @@ -26,9 +26,9 @@ android:layout_marginEnd="0dp" android:layout_gravity="center_vertical | start"> - <TextView + <com.android.systemui.util.SafeMarqueeTextView android:id="@+id/tile_label" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="start" android:textDirection="locale" @@ -37,9 +37,9 @@ android:singleLine="true" android:textAppearance="@style/TextAppearance.QS.TileLabel"/> - <TextView + <com.android.systemui.util.SafeMarqueeTextView android:id="@+id/app_label" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="start" android:textDirection="locale" diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 1b8453ae824d..abc69b080440 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -23,6 +23,9 @@ <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">4</integer> + <!-- Use collapsed layout for media player in landscape QQS --> + <bool name="config_quickSettingsMediaLandscapeCollapsed">false</bool> + <!-- Nav bar button default ordering/layout --> <string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 079f5d0a2805..47822b77a93f 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -102,6 +102,9 @@ <item>one_handed_mode_enabled:onehanded</item> </string-array> + <!-- Use collapsed layout for media player in landscape QQS --> + <bool name="config_quickSettingsMediaLandscapeCollapsed">true</bool> + <!-- Show indicator for Wifi on but not connected. --> <bool name="config_showWifiIndicatorWhenEnabled">false</bool> @@ -683,7 +686,7 @@ <integer name="config_connectionMinDuration">1000</integer> <!-- Flag to activate notification to contents feature --> - <bool name="config_notificationToContents">false</bool> + <bool name="config_notificationToContents">true</bool> <!-- Respect drawable/rounded_secondary.xml intrinsic size for multiple radius corner path customization for secondary display--> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index dba7290dba09..fdb56314bcaa 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -990,6 +990,8 @@ <!-- Sizes for alternate session-based layout --> <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen> <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen> + <dimen name="qs_media_session_height_expanded">184dp</dimen> + <dimen name="qs_media_session_height_collapsed">128dp</dimen> <!-- Size of Smartspace media recommendations cards in the QSPanel carousel --> <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen> diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml new file mode 100644 index 000000000000..c6e18a6f8740 --- /dev/null +++ b/packages/SystemUI/res/xml/media_session_collapsed.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<ConstraintSet + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <Constraint + android:id="@+id/album_art" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_media_session_height_collapsed" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" /> + + <Constraint + android:id="@+id/actionPlayPause" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginEnd="@dimen/qs_media_padding" + app:layout_constraintStart_toEndOf="@id/actionEnd" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" + app:layout_constraintBottom_toBottomOf="parent" /> + + <Constraint + android:id="@+id/actionPrev" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintHorizontal_bias="1" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintStart_toEndOf="@id/header_artist" + app:layout_constraintEnd_toStartOf="@id/media_progress_bar" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" /> + + <Constraint + android:id="@+id/media_progress_bar" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:visibility="gone" + app:layout_constraintStart_toEndOf="@id/actionPrev" + app:layout_constraintEnd_toStartOf="@id/actionNext" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" /> + + <Constraint + android:id="@+id/actionNext" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintStart_toEndOf="@id/media_progress_bar" + app:layout_constraintEnd_toStartOf="@id/actionStart" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" /> + + <Constraint + android:id="@+id/actionStart" + android:layout_width="48dp" + android:layout_height="48dp" + android:visibility="gone" + app:layout_constraintStart_toEndOf="@id/actionNext" + app:layout_constraintEnd_toStartOf="@id/actionEnd" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" /> + + <Constraint + android:id="@+id/actionEnd" + android:layout_width="48dp" + android:layout_height="48dp" + android:visibility="gone" + app:layout_constraintStart_toEndOf="@id/actionStart" + app:layout_constraintEnd_toStartOf="@id/actionPlayPause" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" /> + +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml new file mode 100644 index 000000000000..18ec7aa4cab4 --- /dev/null +++ b/packages/SystemUI/res/xml/media_session_expanded.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<ConstraintSet + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <Constraint + android:id="@+id/album_art" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_media_session_height_expanded" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" /> + + <Constraint + android:id="@+id/actionPlayPause" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginEnd="@dimen/qs_media_padding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/media_seamless" + app:layout_constraintBottom_toTopOf="@id/actionEnd" /> + + <Constraint + android:id="@+id/actionPrev" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/media_progress_bar" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + + <Constraint + android:id="@+id/media_progress_bar" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintStart_toEndOf="@id/actionPrev" + app:layout_constraintEnd_toStartOf="@id/actionNext" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + + <Constraint + android:id="@+id/actionNext" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintStart_toEndOf="@id/media_progress_bar" + app:layout_constraintEnd_toStartOf="@id/actionStart" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + + <Constraint + android:id="@+id/actionStart" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintStart_toEndOf="@id/actionNext" + app:layout_constraintEnd_toStartOf="@id/actionEnd" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + + <Constraint + android:id="@+id/actionEnd" + android:layout_width="48dp" + android:layout_height="48dp" + app:layout_constraintStart_toEndOf="@id/actionStart" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/actionPlayPause" /> + +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java index 8d98a7540a05..56326e36ff5e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java @@ -18,6 +18,7 @@ package com.android.systemui.shared.recents.utilities; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import android.annotation.TargetApi; import android.content.Context; @@ -110,11 +111,16 @@ public class Utilities { hints &= ~NAVIGATION_HINT_BACK_ALT; break; } - if (showImeSwitcher) { + if (imeShown) { hints |= NAVIGATION_HINT_IME_SHOWN; } else { hints &= ~NAVIGATION_HINT_IME_SHOWN; } + if (showImeSwitcher) { + hints |= NAVIGATION_HINT_IME_SWITCHER_SHOWN; + } else { + hints &= ~NAVIGATION_HINT_IME_SWITCHER_SHOWN; + } return hints; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index eebc7918c72c..08b4d3f68a87 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -59,6 +59,7 @@ public class QuickStepContract { public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation"; // See IRecentTasks.aidl public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks"; + public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation"; public static final String NAV_BAR_MODE_3BUTTON_OVERLAY = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 4a0c30ccd798..3d0c08bb5237 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -39,6 +39,8 @@ import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; import com.android.systemui.animation.Interpolators; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -82,6 +84,7 @@ public class SwipeHelper implements Gefingerpoken { private final int mSwipeDirection; private final VelocityTracker mVelocityTracker; private final FalsingManager mFalsingManager; + private final FeatureFlags mFeatureFlags; private float mInitialTouchPos; private float mPerpendicularInitialTouchPos; @@ -128,7 +131,8 @@ public class SwipeHelper implements Gefingerpoken { public SwipeHelper( int swipeDirection, Callback callback, Resources resources, - ViewConfiguration viewConfiguration, FalsingManager falsingManager) { + ViewConfiguration viewConfiguration, FalsingManager falsingManager, + FeatureFlags featureFlags) { mCallback = callback; mHandler = new Handler(); mSwipeDirection = swipeDirection; @@ -146,6 +150,7 @@ public class SwipeHelper implements Gefingerpoken { mFadeDependingOnAmountSwiped = resources.getBoolean( R.bool.config_fadeDependingOnAmountSwiped); mFalsingManager = falsingManager; + mFeatureFlags = featureFlags; mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(), getMaxEscapeAnimDuration() / 1000f); } @@ -795,7 +800,7 @@ public class SwipeHelper implements Gefingerpoken { } private boolean isAvailableToDragAndDrop(View v) { - if (v.getResources().getBoolean(R.bool.config_notificationToContents)) { + if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_DRAG_TO_CONTENTS)) { if (v instanceof ExpandableNotificationRow) { ExpandableNotificationRow enr = (ExpandableNotificationRow) v; boolean canBubble = enr.getEntry().canBubble(); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 357a68fc6502..e1f8f0718077 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -46,9 +46,6 @@ public class Flags { public static final BooleanFlag NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = new BooleanFlag(103, false); - public static final ResourceBooleanFlag NOTIFICATION_SHADE_DRAG = - new ResourceBooleanFlag(104, R.bool.config_enableNotificationShadeDrag); - public static final BooleanFlag NSSL_DEBUG_LINES = new BooleanFlag(105, false); @@ -58,6 +55,9 @@ public class Flags { public static final BooleanFlag NEW_PIPELINE_CRASH_ON_CALL_TO_OLD_PIPELINE = new BooleanFlag(107, false); + public static final ResourceBooleanFlag NOTIFICATION_DRAG_TO_CONTENTS = + new ResourceBooleanFlag(108, R.bool.config_notificationToContents); + /***************************************/ // 200 - keyguard/lockscreen diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 30429fbf8cfa..2a737970907a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -49,7 +49,6 @@ import androidx.slice.builders.SliceAction; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUIAppComponentFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -139,6 +138,8 @@ public class KeyguardSliceProvider extends SliceProvider implements public StatusBarStateController mStatusBarStateController; @Inject public KeyguardBypassController mKeyguardBypassController; + @Inject + public KeyguardUpdateMonitor mKeyguardUpdateMonitor; private CharSequence mMediaTitle; private CharSequence mMediaArtist; protected boolean mDozing; @@ -333,7 +334,7 @@ public class KeyguardSliceProvider extends SliceProvider implements mAlarmManager.cancel(mUpdateNextAlarm); if (mRegistered) { mRegistered = false; - getKeyguardUpdateMonitor().removeCallback(mKeyguardUpdateMonitorCallback); + mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); getContext().unregisterReceiver(mIntentReceiver); } KeyguardSliceProvider.sInstance = null; @@ -389,7 +390,7 @@ public class KeyguardSliceProvider extends SliceProvider implements filter.addAction(Intent.ACTION_LOCALE_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/, null /* scheduler */); - getKeyguardUpdateMonitor().registerCallback(mKeyguardUpdateMonitorCallback); + mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mRegistered = true; } } @@ -441,10 +442,6 @@ public class KeyguardSliceProvider extends SliceProvider implements updateNextAlarm(); } - private KeyguardUpdateMonitor getKeyguardUpdateMonitor() { - return Dependency.get(KeyguardUpdateMonitor.class); - } - /** * Called whenever new media metadata is available. * @param metadata New metadata. diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt index 48f48266fda5..c3f4ce986596 100644 --- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt @@ -45,7 +45,8 @@ class KeyguardMediaController @Inject constructor( private val statusBarStateController: SysuiStatusBarStateController, private val notifLockscreenUserManager: NotificationLockscreenUserManager, private val context: Context, - configurationController: ConfigurationController + configurationController: ConfigurationController, + private val mediaFlags: MediaFlags ) { init { @@ -61,7 +62,11 @@ class KeyguardMediaController @Inject constructor( }) // First let's set the desired state that we want for this host - mediaHost.expansion = MediaHostState.COLLAPSED + mediaHost.expansion = if (mediaFlags.useMediaSessionLayout()) { + MediaHostState.EXPANDED + } else { + MediaHostState.COLLAPSED + } mediaHost.showsOnlyActiveMedia = true mediaHost.falsingProtectionNeeded = true diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 0223c6042499..240ca3678765 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -657,7 +657,10 @@ class MediaDataManager( } val runnable = if (action.actionIntent != null) { Runnable { - if (action.isAuthenticationRequired()) { + if (action.actionIntent.isActivity) { + activityStarter.startPendingIntentDismissingKeyguard( + action.actionIntent) + } else if (action.isAuthenticationRequired()) { activityStarter.dismissKeyguardThenExecute({ var result = sendPendingIntent(action.actionIntent) result diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt index 791a312f341e..591aad1014bd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt @@ -471,14 +471,16 @@ class MediaViewController @Inject constructor( private fun updateMediaViewControllerType(type: TYPE) { this.type = type + + // These XML resources contain ConstraintSets that will apply to this player type's layout when (type) { TYPE.PLAYER -> { collapsedLayout.load(context, R.xml.media_collapsed) expandedLayout.load(context, R.xml.media_expanded) } TYPE.PLAYER_SESSION -> { - collapsedLayout.clone(context, R.layout.media_session_view) - expandedLayout.clone(context, R.layout.media_session_view) + collapsedLayout.load(context, R.xml.media_session_collapsed) + expandedLayout.load(context, R.xml.media_session_expanded) } TYPE.RECOMMENDATION -> { collapsedLayout.load(context, R.xml.media_recommendation_collapsed) diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java index 663877ce1388..f8b34f9769e4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java +++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java @@ -115,12 +115,14 @@ public interface MediaModule { @SysUISingleton static Optional<MediaTttChipControllerReceiver> providesMediaTttChipControllerReceiver( MediaTttFlags mediaTttFlags, + CommandQueue commandQueue, Context context, WindowManager windowManager) { if (!mediaTttFlags.isMediaTttEnabled()) { return Optional.empty(); } - return Optional.of(new MediaTttChipControllerReceiver(context, windowManager)); + return Optional.of( + new MediaTttChipControllerReceiver(commandQueue, context, windowManager)); } /** */ @@ -130,17 +132,12 @@ public interface MediaModule { MediaTttFlags mediaTttFlags, CommandRegistry commandRegistry, Context context, - @Main Executor mainExecutor, - MediaTttChipControllerReceiver mediaTttChipControllerReceiver) { + @Main Executor mainExecutor) { if (!mediaTttFlags.isMediaTttEnabled()) { return Optional.empty(); } return Optional.of( - new MediaTttCommandLineHelper( - commandRegistry, - context, - mainExecutor, - mediaTttChipControllerReceiver)); + new MediaTttCommandLineHelper(commandRegistry, context, mainExecutor)); } /** Inject into NearbyMediaDevicesService. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt index 1ea21ce7728b..26f31cd11704 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -18,16 +18,11 @@ package com.android.systemui.media.taptotransfer import android.app.StatusBarManager import android.content.Context -import android.graphics.Color -import android.graphics.drawable.Icon import android.media.MediaRoute2Info import android.util.Log import androidx.annotation.VisibleForTesting -import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver -import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast import com.android.systemui.media.taptotransfer.sender.TransferFailed @@ -49,14 +44,8 @@ import javax.inject.Inject class MediaTttCommandLineHelper @Inject constructor( commandRegistry: CommandRegistry, private val context: Context, - @Main private val mainExecutor: Executor, - private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver, + @Main private val mainExecutor: Executor ) { - private val appIconDrawable = - Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also { - it.setTint(Color.YELLOW) - } - /** * A map from a display state string typed in the command line to the display int it represents. */ @@ -81,10 +70,7 @@ class MediaTttCommandLineHelper @Inject constructor( init { commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() } - commandRegistry.registerCommand( - ADD_CHIP_COMMAND_RECEIVER_TAG) { AddChipCommandReceiver() } - commandRegistry.registerCommand( - REMOVE_CHIP_COMMAND_RECEIVER_TAG) { RemoveChipCommandReceiver() } + commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() } } /** All commands for the sender device. */ @@ -94,10 +80,11 @@ class MediaTttCommandLineHelper @Inject constructor( .addFeature("feature") .build() + val commandName = args[1] @StatusBarManager.MediaTransferSenderState - val displayState = stateStringToStateInt[args[1]] + val displayState = stateStringToStateInt[commandName] if (displayState == null) { - pw.println("Invalid command name") + pw.println("Invalid command name $commandName") return } @@ -145,27 +132,29 @@ class MediaTttCommandLineHelper @Inject constructor( } } - // TODO(b/216318437): Migrate the receiver callbacks to StatusBarManager. - - /** A command to DISPLAY the media ttt chip on the RECEIVER device. */ - inner class AddChipCommandReceiver : Command { + /** All commands for the receiver device. */ + inner class ReceiverCommand : Command { override fun execute(pw: PrintWriter, args: List<String>) { - mediaTttChipControllerReceiver.displayChip( - ChipStateReceiver(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION) - ) - } - override fun help(pw: PrintWriter) { - pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_RECEIVER_TAG") + val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE) + as StatusBarManager + when(val commandName = args[0]) { + CLOSE_TO_SENDER_STATE -> + statusBarManager.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo + ) + FAR_FROM_SENDER_STATE -> + statusBarManager.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + routeInfo + ) + else -> + pw.println("Invalid command name $commandName") + } } - } - /** A command to REMOVE the media ttt chip on the RECEIVER device. */ - inner class RemoveChipCommandReceiver : Command { - override fun execute(pw: PrintWriter, args: List<String>) { - mediaTttChipControllerReceiver.removeChip() - } override fun help(pw: PrintWriter) { - pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_RECEIVER_TAG") + pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>") } } } @@ -173,13 +162,13 @@ class MediaTttCommandLineHelper @Inject constructor( @VisibleForTesting const val SENDER_COMMAND = "media-ttt-chip-sender" @VisibleForTesting -const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver" +const val RECEIVER_COMMAND = "media-ttt-chip-receiver" @VisibleForTesting -const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver" +const val FAR_FROM_RECEIVER_STATE = "FarFromReceiver" @VisibleForTesting -val FAR_FROM_RECEIVER_STATE = "FarFromReceiver" - -private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon" +const val CLOSE_TO_SENDER_STATE = "CloseToSender" +@VisibleForTesting +const val FAR_FROM_SENDER_STATE = "FarFromSender" private const val CLI_TAG = "MediaTransferCli" private val routeInfo = MediaRoute2Info.Builder("id", "Test Name") diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 17809548d1fd..2d3ca5fdb6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -16,12 +16,18 @@ package com.android.systemui.media.taptotransfer.receiver +import android.app.StatusBarManager import android.content.Context +import android.graphics.Color +import android.graphics.drawable.Icon +import android.media.MediaRoute2Info +import android.util.Log import android.view.ViewGroup import android.view.WindowManager import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon +import com.android.systemui.statusbar.CommandQueue import javax.inject.Inject /** @@ -31,13 +37,49 @@ import javax.inject.Inject */ @SysUISingleton class MediaTttChipControllerReceiver @Inject constructor( + commandQueue: CommandQueue, context: Context, windowManager: WindowManager, ) : MediaTttChipControllerCommon<ChipStateReceiver>( context, windowManager, R.layout.media_ttt_chip_receiver ) { + // TODO(b/216141279): Use app icon from media route info instead of this fake one. + private val fakeAppIconDrawable = + Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also { + it.setTint(Color.YELLOW) + } + + private val commandQueueCallbacks = object : CommandQueue.Callbacks { + override fun updateMediaTapToTransferReceiverDisplay( + @StatusBarManager.MediaTransferReceiverState displayState: Int, + routeInfo: MediaRoute2Info + ) { + this@MediaTttChipControllerReceiver.updateMediaTapToTransferReceiverDisplay( + displayState, routeInfo + ) + } + } + + init { + commandQueue.addCallback(commandQueueCallbacks) + } + + private fun updateMediaTapToTransferReceiverDisplay( + @StatusBarManager.MediaTransferReceiverState displayState: Int, + routeInfo: MediaRoute2Info + ) { + when(displayState) { + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> + displayChip(ChipStateReceiver(fakeAppIconDrawable, routeInfo.name.toString())) + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> removeChip() + else -> + Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState") + } + } override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) { setIcon(chipState, currentChipView) } } + +private const val RECEIVER_TAG = "MediaTapToTransferReceiver" diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 1bef32ad8caf..4b550f2fb875 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -17,7 +17,7 @@ package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; -import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowType; @@ -1410,7 +1410,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, .setFlag(SYSUI_STATE_IME_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0) .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING, - (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0) + (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0) .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY, allowSystemGestureIgnoringBarVisibility()) .commitUpdate(mDisplayId); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 2dd89f3c4dcd..593b278c8278 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -774,11 +774,12 @@ public class NavigationBarView extends FrameLayout implements updateRecentsIcon(); boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode) - && mImeCanRenderGesturalNavButtons; + && mImeCanRenderGesturalNavButtons + && (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0; // Update IME button visibility, a11y and rotate button always overrides the appearance boolean disableImeSwitcher = - (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0 + (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN) == 0 || isImeRenderingNavButtons; mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher, !disableImeSwitcher); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index ec15b2469358..75a3df7cad0c 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -17,7 +17,7 @@ package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; -import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.containsType; @@ -293,7 +293,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, .setFlag(SYSUI_STATE_IME_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0) .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING, - (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0) + (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0) .setFlag(SYSUI_STATE_OVERVIEW_DISABLED, (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0) .setFlag(SYSUI_STATE_HOME_DISABLED, diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index eb3415639db6..58ebe89f199a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -109,7 +109,7 @@ class FgsManagerController @Inject constructor( } isAvailable = deviceConfigProxy - .getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, false) + .getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, true) initialized = true } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java index 2d2fa1f08452..a3af0e58c43d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java @@ -17,12 +17,16 @@ package com.android.systemui.qs; import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL; +import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_COLLAPSED_LANDSCAPE_MEDIA; import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER; +import androidx.annotation.VisibleForTesting; + import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dump.DumpManager; +import com.android.systemui.media.MediaFlags; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.QSTile; @@ -31,6 +35,7 @@ import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.brightness.BrightnessMirrorHandler; import com.android.systemui.statusbar.policy.BrightnessMirrorController; +import com.android.systemui.util.leak.RotationUtils; import java.util.ArrayList; import java.util.List; @@ -54,11 +59,16 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> private final QuickQSBrightnessController mBrightnessController; private final BrightnessMirrorHandler mBrightnessMirrorHandler; + private final MediaFlags mMediaFlags; + private final boolean mUsingCollapsedLandscapeMedia; + @Inject QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost, QSCustomizerController qsCustomizerController, @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer, @Named(QUICK_QS_PANEL) MediaHost mediaHost, + @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia, + MediaFlags mediaFlags, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger, DumpManager dumpManager, QuickQSBrightnessController quickQSBrightnessController @@ -67,17 +77,36 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> uiEventLogger, qsLogger, dumpManager); mBrightnessController = quickQSBrightnessController; mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController); + mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia; + mMediaFlags = mediaFlags; } @Override protected void onInit() { super.onInit(); - mMediaHost.setExpansion(0.0f); + updateMediaExpansion(); mMediaHost.setShowsOnlyActiveMedia(true); mMediaHost.init(MediaHierarchyManager.LOCATION_QQS); mBrightnessController.init(mShouldUseSplitNotificationShade); } + private void updateMediaExpansion() { + int rotation = getRotation(); + boolean isLandscape = rotation == RotationUtils.ROTATION_LANDSCAPE + || rotation == RotationUtils.ROTATION_SEASCAPE; + if (mMediaFlags.useMediaSessionLayout() + && (!mUsingCollapsedLandscapeMedia || !isLandscape)) { + mMediaHost.setExpansion(MediaHost.EXPANDED); + } else { + mMediaHost.setExpansion(MediaHost.COLLAPSED); + } + } + + @VisibleForTesting + protected int getRotation() { + return RotationUtils.getRotation(getContext()); + } + @Override protected void onViewAttached() { super.onViewAttached(); @@ -116,6 +145,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> @Override protected void onConfigurationChanged() { mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade); + updateMediaExpansion(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java index 776ee1021db2..fdf9ae0d4b63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java @@ -16,6 +16,7 @@ package com.android.systemui.qs.dagger; +import static com.android.systemui.util.Utils.useCollapsedMediaInLandscape; import static com.android.systemui.util.Utils.useQsMediaPlayer; import android.content.Context; @@ -56,6 +57,7 @@ public interface QSFragmentModule { String QS_FGS_MANAGER_FOOTER_VIEW = "qs_fgs_manager_footer"; String QS_SECURITY_FOOTER_VIEW = "qs_security_footer"; String QS_USING_MEDIA_PLAYER = "qs_using_media_player"; + String QS_USING_COLLAPSED_LANDSCAPE_MEDIA = "qs_using_collapsed_landscape_media"; /** * Provide a context themed using the QS theme @@ -173,6 +175,13 @@ public interface QSFragmentModule { /** */ @Provides + @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) + static boolean providesQSUsingCollapsedLandscapeMedia(Context context) { + return useCollapsedMediaInLandscape(context.getResources()); + } + + /** */ + @Provides @QSScope static OngoingPrivacyChip providesPrivacyChip(QuickStatusBarHeader qsHeader) { return qsHeader.findViewById(R.id.privacy_chip); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 821dfa5fc902..a712ce2e6394 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -25,6 +25,7 @@ import android.content.res.Configuration import android.content.res.Resources.ID_NULL import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable +import android.os.Trace import android.service.quicksettings.Tile import android.text.TextUtils import android.util.Log @@ -163,6 +164,12 @@ open class QSTileViewImpl @JvmOverloads constructor( updateResources() } + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + Trace.traceBegin(Trace.TRACE_TAG_APP, "QSTileViewImpl#onMeasure") + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + Trace.endSection() + } + override fun resetOverride() { heightOverride = HeightOverrideable.NO_OVERRIDE updateHeight() diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 00a314943f7a..1218fd307931 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -26,6 +26,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; @@ -104,6 +105,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.statusbar.policy.CallbackController; +import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; @@ -163,6 +165,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final Optional<StartingSurface> mStartingSurface; private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController; private final Optional<RecentTasks> mRecentTasks; + private final Optional<BackAnimation> mBackAnimation; private final UiEventLogger mUiEventLogger; private Region mActiveNavBarRegion; @@ -508,6 +511,9 @@ public class OverviewProxyService extends CurrentUserTracker implements mRecentTasks.ifPresent(recentTasks -> params.putBinder( KEY_EXTRA_RECENT_TASKS, recentTasks.createExternalInterface().asBinder())); + mBackAnimation.ifPresent((backAnimation) -> params.putBinder( + KEY_EXTRA_SHELL_BACK_ANIMATION, + backAnimation.createExternalInterface().asBinder())); try { mOverviewProxy.onInitialize(params); @@ -566,6 +572,7 @@ public class OverviewProxyService extends CurrentUserTracker implements Optional<SplitScreen> splitScreenOptional, Optional<OneHanded> oneHandedOptional, Optional<RecentTasks> recentTasks, + Optional<BackAnimation> backAnimation, Optional<StartingSurface> startingSurface, BroadcastDispatcher broadcastDispatcher, ShellTransitions shellTransitions, @@ -593,6 +600,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mOneHandedOptional = oneHandedOptional; mShellTransitions = shellTransitions; mRecentTasks = recentTasks; + mBackAnimation = backAnimation; mUiEventLogger = uiEventLogger; // Assumes device always starts with back button until launcher tells it that it does not diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt new file mode 100644 index 000000000000..6f8e5da70497 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt @@ -0,0 +1,140 @@ +/* + * 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.collection + +import android.view.Choreographer +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.util.ListenerSet +import com.android.systemui.util.concurrency.DelayableExecutor +import dagger.Module +import dagger.Provides + +/** + * Choreographs evaluation resulting from multiple asynchronous sources. Specifically, it exposes + * [schedule], and [addOnEvalListener]; the former will "schedule" an asynchronous invocation of the + * latter. Multiple invocations of [schedule] before any added listeners are invoked have no effect. + */ +interface NotifPipelineChoreographer { + /** + * Schedules all listeners registered with [addOnEvalListener] to be asynchronously executed at + * some point in the future. The exact timing is up to the implementation. + */ + fun schedule() + + /** Cancels a pending evaluation triggered by any recent calls to [schedule]. */ + fun cancel() + + /** Adds a listener [Runnable] that will be invoked when the scheduled evaluation occurs. */ + fun addOnEvalListener(onEvalListener: Runnable) + + /** Removes a listener previously registered with [addOnEvalListener]. */ + fun removeOnEvalListener(onEvalListener: Runnable) +} + +@Module +object NotifPipelineChoreographerModule { + @Provides + @JvmStatic + @SysUISingleton + fun provideChoreographer( + choreographer: Choreographer, + @Main mainExecutor: DelayableExecutor + ): NotifPipelineChoreographer = NotifPipelineChoreographerImpl(choreographer, mainExecutor) +} + +private const val TIMEOUT_MS: Long = 100 + +private class NotifPipelineChoreographerImpl( + private val viewChoreographer: Choreographer, + private val executor: DelayableExecutor +) : NotifPipelineChoreographer { + + private val listeners = ListenerSet<Runnable>() + private var timeoutSubscription: Runnable? = null + private var isScheduled = false + + private val frameCallback = Choreographer.FrameCallback { + if (isScheduled) { + isScheduled = false + timeoutSubscription?.run() + listeners.forEach { it.run() } + } + } + + override fun schedule() { + if (isScheduled) return + isScheduled = true + viewChoreographer.postFrameCallback(frameCallback) + if (!isScheduled) { + // Guard against synchronous evaluation of the frame callback. + return + } + timeoutSubscription = executor.executeDelayed(::onTimeout, TIMEOUT_MS) + } + + override fun cancel() { + if (!isScheduled) return + timeoutSubscription?.run() + viewChoreographer.removeFrameCallback(frameCallback) + } + + override fun addOnEvalListener(onEvalListener: Runnable) { + listeners.addIfAbsent(onEvalListener) + } + + override fun removeOnEvalListener(onEvalListener: Runnable) { + listeners.remove(onEvalListener) + } + + private fun onTimeout() { + if (isScheduled) { + isScheduled = false + viewChoreographer.removeFrameCallback(frameCallback) + listeners.forEach { it.run() } + } + } +} + +class FakeNotifPipelineChoreographer : NotifPipelineChoreographer { + + var isScheduled = false + val listeners = ListenerSet<Runnable>() + + fun runIfScheduled() { + if (isScheduled) { + isScheduled = false + listeners.forEach { it.run() } + } + } + + override fun schedule() { + isScheduled = true + } + + override fun cancel() { + isScheduled = false + } + + override fun addOnEvalListener(onEvalListener: Runnable) { + listeners.addIfAbsent(onEvalListener) + } + + override fun removeOnEvalListener(onEvalListener: Runnable) { + listeners.remove(onEvalListener) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index b328ae8cd0bb..e0c2fd563226 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -122,20 +122,23 @@ public class ShadeListBuilder implements Dumpable { private List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList); private List<ListEntry> mReadOnlyNewNotifList = Collections.unmodifiableList(mNewNotifList); + private final NotifPipelineChoreographer mChoreographer; @Inject public ShadeListBuilder( - SystemClock systemClock, + DumpManager dumpManager, + NotifPipelineChoreographer pipelineChoreographer, NotifPipelineFlags flags, + NotificationInteractionTracker interactionTracker, ShadeListBuilderLogger logger, - DumpManager dumpManager, - NotificationInteractionTracker interactionTracker + SystemClock systemClock ) { Assert.isMainThread(); mSystemClock = systemClock; mLogger = logger; mAlwaysLogList = flags.isDevLoggingEnabled(); mInteractionTracker = interactionTracker; + mChoreographer = pipelineChoreographer; dumpManager.registerDumpable(TAG, this); setSectioners(Collections.emptyList()); @@ -148,6 +151,7 @@ public class ShadeListBuilder implements Dumpable { public void attach(NotifCollection collection) { Assert.isMainThread(); collection.setBuildListener(mReadyForBuildListener); + mChoreographer.addOnEvalListener(this::buildList); } /** @@ -290,7 +294,7 @@ public class ShadeListBuilder implements Dumpable { mLogger.logOnBuildList(); mAllEntries = entries; - buildList(); + mChoreographer.schedule(); } }; @@ -1281,7 +1285,7 @@ public class ShadeListBuilder implements Dumpable { private void rebuildListIfBefore(@PipelineState.StateName int state) { mPipelineState.requireIsBefore(state); if (mPipelineState.is(STATE_IDLE)) { - buildList(); + mChoreographer.schedule(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 45a9092068e4..35d4582d9dee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore; import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl; import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotifPipelineChoreographerModule; import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator; import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator; import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule; @@ -103,6 +104,7 @@ import dagger.Provides; */ @Module(includes = { CoordinatorsModule.class, + NotifPipelineChoreographerModule.class, NotifPanelEventSourceModule.class, NotificationSectionHeadersModule.class, }) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 2436ffdbeefa..c4beb5bf4d7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -27,8 +27,9 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -89,6 +90,7 @@ public class ExpandableNotificationRowController implements NotifViewController private final OnUserInteractionCallback mOnUserInteractionCallback; private final FalsingManager mFalsingManager; private final FalsingCollector mFalsingCollector; + private final FeatureFlags mFeatureFlags; private final boolean mAllowLongPress; private final PeopleNotificationIdentifier mPeopleNotificationIdentifier; private final Optional<BubblesManager> mBubblesManagerOptional; @@ -119,6 +121,7 @@ public class ExpandableNotificationRowController implements NotifViewController OnUserInteractionCallback onUserInteractionCallback, FalsingManager falsingManager, FalsingCollector falsingCollector, + FeatureFlags featureFlags, PeopleNotificationIdentifier peopleNotificationIdentifier, Optional<BubblesManager> bubblesManagerOptional, ExpandableNotificationRowDragController dragController) { @@ -145,6 +148,7 @@ public class ExpandableNotificationRowController implements NotifViewController mOnFeedbackClickListener = mNotificationGutsManager::openGuts; mAllowLongPress = allowLongPress; mFalsingCollector = falsingCollector; + mFeatureFlags = featureFlags; mPeopleNotificationIdentifier = peopleNotificationIdentifier; mBubblesManagerOptional = bubblesManagerOptional; mDragController = dragController; @@ -179,7 +183,7 @@ public class ExpandableNotificationRowController implements NotifViewController ); mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); if (mAllowLongPress) { - if (mView.getResources().getBoolean(R.bool.config_notificationToContents)) { + if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_DRAG_TO_CONTENTS)) { mView.setDragController(mDragController); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index 0b6d7594ce50..7d035a78450a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -35,6 +35,10 @@ public class FooterView extends StackScrollerDecorView { private FooterViewButton mClearAllButton; private FooterViewButton mManageButton; private boolean mShowHistory; + // String cache, for performance reasons. + // Reading them from a Resources object can be quite slow sometimes. + private String mManageNotificationText; + private String mManageNotificationHistoryText; public FooterView(Context context, AttributeSet attrs) { super(context, attrs); @@ -68,6 +72,8 @@ public class FooterView extends StackScrollerDecorView { super.onFinishInflate(); mClearAllButton = (FooterViewButton) findSecondaryView(); mManageButton = findViewById(R.id.manage_text); + updateResources(); + updateText(); } public void setManageButtonClickListener(OnClickListener listener) { @@ -86,15 +92,20 @@ public class FooterView extends StackScrollerDecorView { } public void showHistory(boolean showHistory) { + if (mShowHistory == showHistory) { + return; + } mShowHistory = showHistory; + updateText(); + } + + private void updateText() { if (mShowHistory) { - mManageButton.setText(R.string.manage_notifications_history_text); - mManageButton.setContentDescription( - mContext.getString(R.string.manage_notifications_history_text)); + mManageButton.setText(mManageNotificationHistoryText); + mManageButton.setContentDescription(mManageNotificationHistoryText); } else { - mManageButton.setText(R.string.manage_notifications_text); - mManageButton.setContentDescription( - mContext.getString(R.string.manage_notifications_text)); + mManageButton.setText(mManageNotificationText); + mManageButton.setContentDescription(mManageNotificationText); } } @@ -109,7 +120,8 @@ public class FooterView extends StackScrollerDecorView { mClearAllButton.setText(R.string.clear_all_notifications_text); mClearAllButton.setContentDescription( mContext.getString(R.string.accessibility_clear_all)); - showHistory(mShowHistory); + updateResources(); + updateText(); } /** @@ -124,6 +136,12 @@ public class FooterView extends StackScrollerDecorView { mManageButton.setTextColor(textColor); } + private void updateResources() { + mManageNotificationText = getContext().getString(R.string.manage_notifications_text); + mManageNotificationHistoryText = getContext() + .getString(R.string.manage_notifications_history_text); + } + @Override public ExpandableViewState createExpandableViewState() { return new FooterViewState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index ce3e27c55f3e..f40a3c7186e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -76,7 +76,10 @@ public class AmbientState { private float mHideAmount; private boolean mAppearing; private float mPulseHeight = MAX_PULSE_HEIGHT; + + /** How we much we are sleeping. 1f fully dozing (AOD), 0f fully awake (for all other states) */ private float mDozeAmount = 0.0f; + private Runnable mOnPulseHeightChangedListener; private ExpandableNotificationRow mTrackedHeadsUpRow; private float mAppearFraction; @@ -96,6 +99,9 @@ public class AmbientState { /** Height of the notifications panel without top padding when expansion completes. */ private float mStackEndHeight; + /** Whether we are swiping up. */ + private boolean mIsSwipingUp; + /** * @return Height of the notifications panel without top padding when expansion completes. */ @@ -133,6 +139,20 @@ public class AmbientState { } /** + * @param isSwipingUp Whether we are swiping up. + */ + public void setSwipingUp(boolean isSwipingUp) { + mIsSwipingUp = isSwipingUp; + } + + /** + * @return Whether we are swiping up. + */ + public boolean isSwipingUp() { + return mIsSwipingUp; + } + + /** * @return Fraction of shade expansion. */ public float getExpansionFraction() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 25b8a6545638..2c4db7745fd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -203,6 +203,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private float mQsExpansionFraction; private final int mSplitShadeMinContentHeight; + /** Whether we are flinging the shade open or closed. */ + private boolean mIsFlinging; + /** * The algorithm which calculates the properties for our children */ @@ -1270,6 +1273,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } /** + * @return Whether we should skip stack height update for lockscreen swipe-up or unlock hint. + */ + private boolean shouldSkipHeightUpdate() { + // After the user swipes up on lockscreen and lets go, + // {@link PanelViewController) flings the shade back down. + return mAmbientState.isOnKeyguard() && ( + mAmbientState.isUnlockHintRunning() || mAmbientState.isSwipingUp() || mIsFlinging); + } + + /** * Apply expansion fraction to the y position and height of the notifications panel. * @param listenerNeedsAnimation does the listener need to animate? */ @@ -1283,7 +1296,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (mOnStackYChanged != null) { mOnStackYChanged.accept(listenerNeedsAnimation); } - if (mQsExpansionFraction <= 0) { + if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) { final float endHeight = updateStackEndHeight( getHeight(), getEmptyBottomMargin(), mTopPadding); updateStackHeight(endHeight, fraction); @@ -1325,22 +1338,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) public void setExpandedHeight(float height) { final float shadeBottom = getHeight() - getEmptyBottomMargin(); - final float expansionFraction = MathUtils.saturate(height / shadeBottom); - mAmbientState.setExpansionFraction(expansionFraction); + final boolean skipHeightUpdate = shouldSkipHeightUpdate(); + if (!skipHeightUpdate) { + final float expansionFraction = MathUtils.saturate(height / shadeBottom); + mAmbientState.setExpansionFraction(expansionFraction); + } updateStackPosition(); - mExpandedHeight = height; - setIsExpanded(height > 0); - int minExpansionHeight = getMinExpansionHeight(); - if (height < minExpansionHeight) { - mClipRect.left = 0; - mClipRect.right = getWidth(); - mClipRect.top = 0; - mClipRect.bottom = (int) height; - height = minExpansionHeight; - setRequestedClipBounds(mClipRect); - } else { - setRequestedClipBounds(null); + if (!skipHeightUpdate) { + mExpandedHeight = height; + setIsExpanded(height > 0); + int minExpansionHeight = getMinExpansionHeight(); + if (height < minExpansionHeight) { + mClipRect.left = 0; + mClipRect.right = getWidth(); + mClipRect.top = 0; + mClipRect.bottom = (int) height; + height = minExpansionHeight; + setRequestedClipBounds(mClipRect); + } else { + setRequestedClipBounds(null); + } } int stackHeight; float translationY; @@ -1368,7 +1386,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } } else { - stackHeight = (int) height; + stackHeight = (int) (skipHeightUpdate ? mExpandedHeight : height); } } else { appearFraction = calculateAppearFraction(height); @@ -1386,7 +1404,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } mAmbientState.setAppearFraction(appearFraction); - if (stackHeight != mCurrentStackHeight) { + if (stackHeight != mCurrentStackHeight && !skipHeightUpdate) { mCurrentStackHeight = stackHeight; updateAlgorithmHeightAndPadding(); requestChildrenUpdate(); @@ -5001,6 +5019,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mAmbientState.setUnlockHintRunning(running); } + /** + * @param isFlinging Whether we are flinging the shade open or closed. + */ + public void setIsFlinging(boolean isFlinging) { + mIsFlinging = isFlinging; + } + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) { mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index a2929f01f715..e1116f84c15d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1195,6 +1195,13 @@ public class NotificationStackScrollLayoutController { mView.setUnlockHintRunning(running); } + /** + * @param isFlinging Whether we are flinging the shade open or close. + */ + public void setIsFlinging(boolean isFlinging) { + mView.setIsFlinging(isFlinging); + } + public boolean isFooterViewNotGone() { return mView.isFooterViewNotGone(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 1038e76234ae..2d2fbe588728 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -33,6 +33,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.SwipeHelper; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; @@ -66,9 +67,10 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc NotificationSwipeHelper( Resources resources, ViewConfiguration viewConfiguration, - FalsingManager falsingManager, int swipeDirection, NotificationCallback callback, + FalsingManager falsingManager, FeatureFlags featureFlags, + int swipeDirection, NotificationCallback callback, NotificationMenuRowPlugin.OnMenuEventListener menuListener) { - super(swipeDirection, callback, resources, viewConfiguration, falsingManager); + super(swipeDirection, callback, resources, viewConfiguration, falsingManager, featureFlags); mMenuListener = menuListener; mCallback = callback; mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */); @@ -508,16 +510,18 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc private final Resources mResources; private final ViewConfiguration mViewConfiguration; private final FalsingManager mFalsingManager; + private final FeatureFlags mFeatureFlags; private int mSwipeDirection; private NotificationCallback mNotificationCallback; private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener; @Inject Builder(@Main Resources resources, ViewConfiguration viewConfiguration, - FalsingManager falsingManager) { + FalsingManager falsingManager, FeatureFlags featureFlags) { mResources = resources; mViewConfiguration = viewConfiguration; mFalsingManager = falsingManager; + mFeatureFlags = featureFlags; } Builder setSwipeDirection(int swipeDirection) { @@ -538,7 +542,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc NotificationSwipeHelper build() { return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager, - mSwipeDirection, mNotificationCallback, mOnMenuEventListener); + mFeatureFlags, mSwipeDirection, mNotificationCallback, mOnMenuEventListener); } } } 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 3d3a1da1cf82..278b4ec5f53a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -806,7 +806,6 @@ public class NotificationPanelViewController extends PanelViewController QsFrameTranslateController qsFrameTranslateController, KeyguardUnlockAnimationController keyguardUnlockAnimationController) { super(view, - featureFlags, falsingManager, dozeLog, keyguardStateController, @@ -1885,9 +1884,16 @@ public class NotificationPanelViewController extends PanelViewController mHeadsUpTouchHelper.notifyFling(!expand); mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */); setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f); + mNotificationStackScrollLayoutController.setIsFlinging(true); super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); } + @Override + protected void onFlingEnd(boolean cancelled) { + super.onFlingEnd(cancelled); + mNotificationStackScrollLayoutController.setIsFlinging(false); + } + private boolean onQsIntercept(MotionEvent event) { int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index c466a8ce6d3f..85e804233ed9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -53,8 +53,6 @@ import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.classifier.Classifier; import com.android.systemui.doze.DozeLog; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -223,7 +221,6 @@ public abstract class PanelViewController { public PanelViewController( PanelView view, - FeatureFlags featureFlags, FalsingManager falsingManager, DozeLog dozeLog, KeyguardStateController keyguardStateController, @@ -292,7 +289,8 @@ public abstract class PanelViewController { mBounceInterpolator = new BounceInterpolator(); mFalsingManager = falsingManager; mDozeLog = dozeLog; - mNotificationsDragEnabled = featureFlags.isEnabled(Flags.NOTIFICATION_SHADE_DRAG); + mNotificationsDragEnabled = mResources.getBoolean( + R.bool.config_enableNotificationShadeDrag); mVibratorHelper = vibratorHelper; mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation); mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; @@ -461,7 +459,7 @@ public abstract class PanelViewController { boolean expands = onEmptySpaceClick(mInitialTouchX); onTrackingStopped(expands); } - + mAmbientState.setSwipingUp(false); mVelocityTracker.clear(); } @@ -708,7 +706,7 @@ public abstract class PanelViewController { animator.start(); } - private void onFlingEnd(boolean cancelled) { + void onFlingEnd(boolean cancelled) { mIsFlinging = false; // No overshoot when the animation ends setOverExpansionInternal(0, false /* isFromGesture */); @@ -1393,6 +1391,10 @@ public abstract class PanelViewController { mUpwardsWhenThresholdReached = isDirectionUpwards(x, y); } if ((!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) { + // Count h==0 as part of swipe-up, + // otherwise {@link NotificationStackScrollLayout} + // wrongly enables stack height updates at the start of lockscreen swipe-up + mAmbientState.setSwipingUp(h <= 0); setExpandedHeightInternal(newHeight); } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index 329293409dc2..d464acb7fe76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -217,8 +217,10 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { * frameworks/base/core/res/res/values/config.xml */ public void addIgnoredSlot(String slotName) { - addIgnoredSlotInternal(slotName); - requestLayout(); + boolean added = addIgnoredSlotInternal(slotName); + if (added) { + requestLayout(); + } } /** @@ -226,17 +228,27 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { * @param slots names of the icons to ignore */ public void addIgnoredSlots(List<String> slots) { + boolean willAddAny = false; for (String slot : slots) { - addIgnoredSlotInternal(slot); + willAddAny |= addIgnoredSlotInternal(slot); } - requestLayout(); + if (willAddAny) { + requestLayout(); + } } - private void addIgnoredSlotInternal(String slotName) { - if (!mIgnoredSlots.contains(slotName)) { - mIgnoredSlots.add(slotName); + /** + * + * @param slotName + * @return + */ + private boolean addIgnoredSlotInternal(String slotName) { + if (mIgnoredSlots.contains(slotName)) { + return false; } + mIgnoredSlots.add(slotName); + return true; } /** @@ -245,9 +257,10 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { * @param slotName name of the icon slot to remove from the ignored list */ public void removeIgnoredSlot(String slotName) { - mIgnoredSlots.remove(slotName); - - requestLayout(); + boolean removed = mIgnoredSlots.remove(slotName); + if (removed) { + requestLayout(); + } } /** @@ -256,11 +269,14 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { * @param slots name of the icon slots to remove from the ignored list */ public void removeIgnoredSlots(List<String> slots) { + boolean removedAny = false; for (String slot : slots) { - mIgnoredSlots.remove(slot); + removedAny |= mIgnoredSlots.remove(slot); } - requestLayout(); + if (removedAny) { + requestLayout(); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java b/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java index 09dbfee5e0a4..fa4f314ff0a2 100644 --- a/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java +++ b/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java @@ -19,7 +19,6 @@ package com.android.systemui.util; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; -import android.widget.TextView; /** * TextView that changes its ellipsize value with its visibility. @@ -27,7 +26,7 @@ import android.widget.TextView; * The View responds to changes in user-visibility to change its ellipsize from MARQUEE to END * and back. Useful for TextView that need to marquee forever. */ -public class AutoMarqueeTextView extends TextView { +public class AutoMarqueeTextView extends SafeMarqueeTextView { private boolean mAggregatedVisible = false; diff --git a/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt b/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt new file mode 100644 index 000000000000..1c1a990e6018 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt @@ -0,0 +1,44 @@ +package com.android.systemui.util + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import android.widget.TextView + +/** + * A TextField that doesn't relayout when changing from marquee to ellipsis. + */ +@SuppressLint("AppCompatCustomView") +open class SafeMarqueeTextView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextView(context, attrs, defStyleAttr, defStyleRes) { + + private var safelyIgnoreLayout = false + private val hasStableWidth + get() = layoutParams.width != ViewGroup.LayoutParams.WRAP_CONTENT + + override fun requestLayout() { + if (safelyIgnoreLayout) { + return + } + super.requestLayout() + } + + override fun startMarquee() { + val wasIgnoring = safelyIgnoreLayout + safelyIgnoreLayout = hasStableWidth + super.startMarquee() + safelyIgnoreLayout = wasIgnoring + } + + override fun stopMarquee() { + val wasIgnoring = safelyIgnoreLayout + safelyIgnoreLayout = hasStableWidth + super.stopMarquee() + safelyIgnoreLayout = wasIgnoring + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index 407dc5e2787a..71d8e3344937 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -162,6 +162,14 @@ public class Utils { } /** + * Returns true if the device should use the collapsed layout for the media player when in + * landscape (or seascape) orientation + */ + public static boolean useCollapsedMediaInLandscape(Resources resources) { + return resources.getBoolean(R.bool.config_quickSettingsMediaLandscapeCollapsed); + } + + /** * Returns true if the device should use the split notification shade, based on orientation and * screen width. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index d1f505baa9e3..51c258055465 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -90,6 +90,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { private DozeParameters mDozeParameters; @Mock private NextAlarmController mNextAlarmController; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private TestableKeyguardSliceProvider mProvider; private boolean mIsZenMode; @@ -97,7 +98,6 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); - mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class); mIsZenMode = false; mProvider = new TestableKeyguardSliceProvider(); mProvider.setContextAvailableCallback(context -> { }); @@ -265,6 +265,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { mStatusBarStateController = KeyguardSliceProviderTest.this.mStatusBarStateController; mKeyguardBypassController = KeyguardSliceProviderTest.this.mKeyguardBypassController; mMediaManager = KeyguardSliceProviderTest.this.mNotificationMediaManager; + mKeyguardUpdateMonitor = KeyguardSliceProviderTest.this.mKeyguardUpdateMonitor; } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt index dc7026da2194..1484c9d11ba6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt @@ -36,6 +36,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.`when` as whenever @@ -51,6 +52,8 @@ class KeyguardMediaControllerTest : SysuiTestCase() { private lateinit var statusBarStateController: SysuiStatusBarStateController @Mock private lateinit var configurationController: ConfigurationController + @Mock + private lateinit var mediaFlags: MediaFlags @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager @@ -70,13 +73,15 @@ class KeyguardMediaControllerTest : SysuiTestCase() { .thenReturn(true) whenever(mediaHost.hostView).thenReturn(hostView) hostView.layoutParams = FrameLayout.LayoutParams(100, 100) + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false) keyguardMediaController = KeyguardMediaController( mediaHost, bypassController, statusBarStateController, notificationLockscreenUserManager, context, - configurationController + configurationController, + mediaFlags ) keyguardMediaController.attachSinglePaneContainer(mediaContainerView) keyguardMediaController.useSplitShade = false @@ -150,4 +155,24 @@ class KeyguardMediaControllerTest : SysuiTestCase() { assertTrue("HostView wasn't attached to the single pane container", mediaContainerView.childCount == 1) } + + @Test + fun testNotificationLayout_collapsedPlayer() { + verify(mediaHost).expansion = MediaHostState.COLLAPSED + } + + @Test + fun testSessionLayout_expandedPlayer() { + whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true) + keyguardMediaController = KeyguardMediaController( + mediaHost, + bypassController, + statusBarStateController, + notificationLockscreenUserManager, + context, + configurationController, + mediaFlags + ) + verify(mediaHost).expansion = MediaHostState.EXPANDED + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt index c3d8d245baed..cb05d0302698 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt @@ -21,8 +21,6 @@ import android.content.Context import android.media.MediaRoute2Info import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver -import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast import com.android.systemui.media.taptotransfer.sender.TransferFailed @@ -62,8 +60,6 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Mock private lateinit var statusBarManager: StatusBarManager - @Mock - private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver @Before fun setUp() { @@ -74,7 +70,6 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { commandRegistry, context, FakeExecutor(FakeSystemClock()), - mediaTttChipControllerReceiver, ) } @@ -86,21 +81,10 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { } @Test(expected = IllegalStateException::class) - fun constructor_addReceiverCommandAlreadyRegistered() { - // Since creating the chip controller should automatically register the add command, it - // should throw when registering it again. - commandRegistry.registerCommand( - ADD_CHIP_COMMAND_RECEIVER_TAG - ) { EmptyCommand() } - } - - @Test(expected = IllegalStateException::class) - fun constructor_removeReceiverCommandAlreadyRegistered() { - // Since creating the chip controller should automatically register the remove command, it + fun constructor_receiverCommandAlreadyRegistered() { + // Since creating the chip controller should automatically register the receiver command, it // should throw when registering it again. - commandRegistry.registerCommand( - REMOVE_CHIP_COMMAND_RECEIVER_TAG - ) { EmptyCommand() } + commandRegistry.registerCommand(RECEIVER_COMMAND) { EmptyCommand() } } @Test @@ -214,22 +198,31 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { } @Test - fun receiver_addCommand_chipAdded() { - commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG)) + fun receiver_closeToSender_serviceCallbackCalled() { + commandRegistry.onShellCommand(pw, getReceiverCommand(CLOSE_TO_SENDER_STATE)) - verify(mediaTttChipControllerReceiver).displayChip(any(ChipStateReceiver::class.java)) + verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( + eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER), + any() + ) } @Test - fun receiver_removeCommand_chipRemoved() { - commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_RECEIVER_TAG)) + fun receiver_farFromSender_serviceCallbackCalled() { + commandRegistry.onShellCommand(pw, getReceiverCommand(FAR_FROM_SENDER_STATE)) - verify(mediaTttChipControllerReceiver).removeChip() + verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( + eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER), + any() + ) } private fun getSenderCommand(displayState: String): Array<String> = arrayOf(SENDER_COMMAND, DEVICE_NAME, displayState) + private fun getReceiverCommand(displayState: String): Array<String> = + arrayOf(RECEIVER_COMMAND, displayState) + class EmptyCommand : Command { override fun execute(pw: PrintWriter, args: List<String>) { } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 1d1265b16e63..fce495470ab0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -16,7 +16,9 @@ package com.android.systemui.media.taptotransfer.receiver +import android.app.StatusBarManager import android.graphics.drawable.Icon +import android.media.MediaRoute2Info import android.view.View import android.view.ViewGroup import android.view.WindowManager @@ -24,6 +26,7 @@ import android.widget.ImageView import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -31,7 +34,8 @@ import org.junit.Ignore import org.junit.Test import org.mockito.ArgumentCaptor import org.mockito.Mock -import org.mockito.Mockito +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @@ -41,11 +45,55 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { @Mock private lateinit var windowManager: WindowManager + @Mock + private lateinit var commandQueue: CommandQueue + private lateinit var commandQueueCallback: CommandQueue.Callbacks @Before fun setUp() { MockitoAnnotations.initMocks(this) - controllerReceiver = MediaTttChipControllerReceiver(context, windowManager) + controllerReceiver = MediaTttChipControllerReceiver(commandQueue, context, windowManager) + + val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java) + verify(commandQueue).addCallback(callbackCaptor.capture()) + commandQueueCallback = callbackCaptor.value!! + } + + @Test + fun commandQueueCallback_closeToSender_triggersChip() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo + ) + + assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(ROUTE_NAME) + } + + @Test + fun commandQueueCallback_farFromSender_noChipShown() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + routeInfo + ) + + verify(windowManager, never()).addView(any(), any()) + } + + @Test + fun commandQueueCallback_closeThenFar_chipShownThenHidden() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo + ) + + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + routeInfo + ) + + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + verify(windowManager).removeView(viewCaptor.value) } @Test @@ -61,9 +109,14 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { private fun getChipView(): ViewGroup { val viewCaptor = ArgumentCaptor.forClass(View::class.java) - Mockito.verify(windowManager).addView(viewCaptor.capture(), any()) + verify(windowManager).addView(viewCaptor.capture(), any()) return viewCaptor.value as ViewGroup } private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) } + +private const val ROUTE_NAME = "Test name" +private val routeInfo = MediaRoute2Info.Builder("id", ROUTE_NAME) + .addFeature("feature") + .build() 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 9ca898b9dea9..612bad8483d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -18,6 +18,7 @@ package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.inputmethodservice.InputMethodService.IME_VISIBLE; @@ -285,20 +286,26 @@ public class NavigationBarTest extends SysuiTestCase { BACK_DISPOSITION_DEFAULT, true); // Verify IME window state will be updated in default NavBar & external NavBar state reset. - assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, + assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN + | NAVIGATION_HINT_IME_SWITCHER_SHOWN, defaultNavBar.getNavigationIconHints()); assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) + != 0); externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); defaultNavBar.setImeWindowStatus( DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false); // Verify IME window state will be updated in external NavBar & default NavBar state reset. - assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, + assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN + | NAVIGATION_HINT_IME_SWITCHER_SHOWN, externalNavBar.getNavigationIconHints()); assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) + != 0); } @Test @@ -316,6 +323,8 @@ public class NavigationBarTest extends SysuiTestCase { BACK_DISPOSITION_DEFAULT, true); assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) + != 0); // Verify navbar didn't alter and showing back icon when the keyguard is showing without // requesting IME insets visible. @@ -324,6 +333,8 @@ public class NavigationBarTest extends SysuiTestCase { BACK_DISPOSITION_DEFAULT, true); assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) + != 0); // Verify navbar altered and showing back icon when the keyguard is showing and // requesting IME insets visible. @@ -333,6 +344,8 @@ public class NavigationBarTest extends SysuiTestCase { BACK_DISPOSITION_DEFAULT, true); assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) + != 0); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt index 09c6d9e86a44..1eb16fd64b85 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt @@ -23,11 +23,14 @@ import com.android.internal.logging.MetricsLogger import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager +import com.android.systemui.media.MediaFlags import com.android.systemui.media.MediaHost +import com.android.systemui.media.MediaHostState import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.qs.QSTileView import com.android.systemui.qs.customize.QSCustomizerController import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.util.leak.RotationUtils import org.junit.After import org.junit.Before import org.junit.Test @@ -55,6 +58,8 @@ class QuickQSPanelControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost @Mock + private lateinit var mediaFlags: MediaFlags + @Mock private lateinit var metricsLogger: MetricsLogger private val uiEventLogger = UiEventLoggerFake() @Mock @@ -71,7 +76,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() { @Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener> - private lateinit var controller: QuickQSPanelController + private lateinit var controller: TestQuickQSPanelController @Before fun setUp() { @@ -82,13 +87,16 @@ class QuickQSPanelControllerTest : SysuiTestCase() { `when`(quickQSPanel.dumpableTag).thenReturn("") `when`(quickQSPanel.resources).thenReturn(mContext.resources) `when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView) + `when`(mediaFlags.useMediaSessionLayout()).thenReturn(false) - controller = QuickQSPanelController( + controller = TestQuickQSPanelController( quickQSPanel, qsTileHost, qsCustomizerController, false, mediaHost, + true, + mediaFlags, metricsLogger, uiEventLogger, qsLogger, @@ -133,4 +141,49 @@ class QuickQSPanelControllerTest : SysuiTestCase() { verify(quickQsBrightnessController).refreshVisibility(anyBoolean()) } + + @Test + fun testMediaExpansionUpdatedWhenConfigurationChanged() { + `when`(mediaFlags.useMediaSessionLayout()).thenReturn(true) + + // times(2) because both controller and base controller are registering their listeners + verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture()) + + captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) } + verify(mediaHost).expansion = MediaHostState.EXPANDED + + // Rotate device, verify media size updated + controller.setRotation(RotationUtils.ROTATION_LANDSCAPE) + captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) } + + // times(2) because init will have set to collapsed because the flag was off + verify(mediaHost, times(2)).expansion = MediaHostState.COLLAPSED + } + + class TestQuickQSPanelController( + view: QuickQSPanel, + qsTileHost: QSTileHost, + qsCustomizerController: QSCustomizerController, + usingMediaPlayer: Boolean, + mediaHost: MediaHost, + usingCollapsedLandscapeMedia: Boolean, + mediaFlags: MediaFlags, + metricsLogger: MetricsLogger, + uiEventLogger: UiEventLoggerFake, + qsLogger: QSLogger, + dumpManager: DumpManager, + quickQSBrightnessController: QuickQSBrightnessController + ) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer, + mediaHost, usingCollapsedLandscapeMedia, mediaFlags, metricsLogger, uiEventLogger, qsLogger, + dumpManager, quickQSBrightnessController) { + + private var rotation = RotationUtils.ROTATION_NONE + + @Override + override fun getRotation(): Int = rotation + + fun setRotation(newRotation: Int) { + rotation = newRotation + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt new file mode 100644 index 000000000000..3820b98ab632 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt @@ -0,0 +1,100 @@ +/* + * 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.collection + +import android.testing.AndroidTestingRunner +import android.view.Choreographer +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.withArgCaptor +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.anyLong +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class NotifPipelineChoreographerTest : SysuiTestCase() { + + val viewChoreographer: Choreographer = mock() + val timeoueSubscription: Runnable = mock() + val executor: DelayableExecutor = mock<DelayableExecutor>().also { + whenever(it.executeDelayed(any(), anyLong())).thenReturn(timeoueSubscription) + } + + val pipelineChoreographer: NotifPipelineChoreographer = NotifPipelineChoreographerModule + .provideChoreographer(viewChoreographer, executor) + + @Test + fun scheduleThenEvalFrameCallback() { + // GIVEN a registered eval listener and scheduled choreographer + var hasEvaluated = false + pipelineChoreographer.addOnEvalListener { + hasEvaluated = true + } + pipelineChoreographer.schedule() + val frameCallback: Choreographer.FrameCallback = withArgCaptor { + verify(viewChoreographer).postFrameCallback(capture()) + } + // WHEN the choreographer would invoke its callback + frameCallback.doFrame(0) + // THEN the choreographer would evaluate, and the timeoutSubscription would have been + // cancelled + assertTrue(hasEvaluated) + verify(timeoueSubscription).run() + } + + @Test + fun scheduleThenEvalTimeoutCallback() { + // GIVEN a registered eval listener and scheduled choreographer + var hasEvaluated = false + pipelineChoreographer.addOnEvalListener { + hasEvaluated = true + } + pipelineChoreographer.schedule() + val frameCallback: Choreographer.FrameCallback = withArgCaptor { + verify(viewChoreographer).postFrameCallback(capture()) + } + val runnable: Runnable = withArgCaptor { + verify(executor).executeDelayed(capture(), anyLong()) + } + // WHEN the executor would invoke its callback (indicating a timeout) + runnable.run() + // THEN the choreographer would evaluate, and the FrameCallback would have been unregistered + assertTrue(hasEvaluated) + verify(viewChoreographer).removeFrameCallback(frameCallback) + } + + @Test + fun scheduleThenCancel() { + // GIVEN a scheduled choreographer + pipelineChoreographer.schedule() + val frameCallback: Choreographer.FrameCallback = withArgCaptor { + verify(viewChoreographer).postFrameCallback(capture()) + } + // WHEN the scheduled run is cancelled + pipelineChoreographer.cancel() + // THEN both the FrameCallback is unregistered and the timeout subscription is cancelled. + verify(viewChoreographer).removeFrameCallback(frameCallback) + verify(timeoueSubscription).run() + } +}
\ No newline at end of file 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 cb248b05e4bd..f470715b92c4 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 @@ -111,6 +111,8 @@ public class ShadeListBuilderTest extends SysuiTestCase { @Captor private ArgumentCaptor<CollectionReadyForBuildListener> mBuildListenerCaptor; + private final FakeNotifPipelineChoreographer mPipelineChoreographer = + new FakeNotifPipelineChoreographer(); private CollectionReadyForBuildListener mReadyForBuildListener; private List<NotificationEntryBuilder> mPendingSet = new ArrayList<>(); private List<NotificationEntry> mEntrySet = new ArrayList<>(); @@ -127,11 +129,12 @@ public class ShadeListBuilderTest extends SysuiTestCase { allowTestableLooperAsMainThread(); mListBuilder = new ShadeListBuilder( - mSystemClock, + mDumpManager, + mPipelineChoreographer, mNotifPipelineFlags, + mInteractionTracker, mLogger, - mDumpManager, - mInteractionTracker + mSystemClock ); mListBuilder.setOnRenderListListener(mOnRenderListListener); @@ -567,6 +570,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN the pipeline is kicked off mReadyForBuildListener.onBuildList(singletonList(entry)); + mPipelineChoreographer.runIfScheduled(); // THEN the entry's initialization time is reset assertFalse(entry.hasFinishedInitialization()); @@ -1024,26 +1028,38 @@ public class ShadeListBuilderTest extends SysuiTestCase { clearInvocations(mOnRenderListListener); packageFilter.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); idPromoter.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); section.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); hypeComparator.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); sectionComparator.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); preRenderInvalidator.invalidateList(); + assertTrue(mPipelineChoreographer.isScheduled()); + mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); } @@ -1515,6 +1531,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN visual stability manager allows group changes again mStabilityManager.setAllowGroupChanges(true); mStabilityManager.invalidateList(); + mPipelineChoreographer.runIfScheduled(); // THEN entries are grouped verifyBuiltList( @@ -1553,6 +1570,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN section changes are allowed again mStabilityManager.setAllowSectionChanges(true); mStabilityManager.invalidateList(); + mPipelineChoreographer.runIfScheduled(); // THEN the section updates assertEquals(newSectioner, mEntrySet.get(0).getSection().getSectioner()); @@ -1773,6 +1791,30 @@ public class ShadeListBuilderTest extends SysuiTestCase { } @Test + public void testMultipleInvalidationsCoalesce() { + // GIVEN a PreGroupFilter and a FinalizeFilter + NotifFilter filter1 = new PackageFilter(PACKAGE_5); + NotifFilter filter2 = new PackageFilter(PACKAGE_0); + mListBuilder.addPreGroupFilter(filter1); + mListBuilder.addFinalizeFilter(filter2); + + // WHEN both filters invalidate + filter1.invalidateList(); + filter2.invalidateList(); + + // THEN the pipeline choreographer is scheduled to evaluate, AND the pipeline hasn't + // actually run. + assertTrue(mPipelineChoreographer.isScheduled()); + verify(mOnRenderListListener, never()).onRenderList(anyList()); + + // WHEN the pipeline choreographer actually runs + mPipelineChoreographer.runIfScheduled(); + + // THEN the pipeline runs + verify(mOnRenderListListener).onRenderList(anyList()); + } + + @Test public void testIsSorted() { Comparator<Integer> intCmp = Integer::compare; assertTrue(ShadeListBuilder.isSorted(Collections.emptyList(), intCmp)); @@ -1914,6 +1956,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { } mReadyForBuildListener.onBuildList(mEntrySet); + mPipelineChoreographer.runIfScheduled(); } private void verifyBuiltList(ExpectedEntry ...expectedEntries) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index a890414115dd..52189e417017 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -48,6 +48,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -273,6 +274,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { null, new FalsingManagerFake(), new FalsingCollectorFake(), + mock(FeatureFlags.class), mPeopleNotificationIdentifier, Optional.of(mock(BubblesManager.class)), mock(ExpandableNotificationRowDragController.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index a0e91fc77148..1305d79e4648 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -42,6 +42,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SwipeHelper; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -71,6 +72,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { private Handler mHandler; private ExpandableNotificationRow mNotificationRow; private Runnable mFalsingCheck; + private FeatureFlags mFeatureFlags; @Rule public MockitoRule mockito = MockitoJUnit.rule(); @@ -78,9 +80,10 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { public void setUp() throws Exception { mCallback = mock(NotificationSwipeHelper.NotificationCallback.class); mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class); + mFeatureFlags = mock(FeatureFlags.class); mSwipeHelper = spy(new NotificationSwipeHelper( mContext.getResources(), ViewConfiguration.get(mContext), - new FalsingManagerFake(), SwipeHelper.X, mCallback, mListener)); + new FalsingManagerFake(), mFeatureFlags, SwipeHelper.X, mCallback, mListener)); mView = mock(View.class); mEvent = mock(MotionEvent.class); mMenuRow = mock(NotificationMenuRowPlugin.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index dee88dbfe29d..7347565408f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -37,7 +37,6 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -99,7 +98,6 @@ import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.doze.DozeLog; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.idle.IdleHostViewController; @@ -394,7 +392,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mConfiguration.orientation = ORIENTATION_PORTRAIT; when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); mDisplayMetrics.density = 100; - when(mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHADE_DRAG)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true); when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade)) .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE); when(mResources.getDimensionPixelSize(R.dimen.qs_panel_width)).thenReturn(400); diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index 6938e25ea9af..c9903ea19868 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -43,6 +43,7 @@ import android.hardware.camera2.extension.IImageProcessorImpl; import android.hardware.camera2.extension.IInitializeSessionCallback; import android.hardware.camera2.extension.IPreviewExtenderImpl; import android.hardware.camera2.extension.IPreviewImageProcessorImpl; +import android.hardware.camera2.extension.IProcessResultImpl; import android.hardware.camera2.extension.IRequestCallback; import android.hardware.camera2.extension.IRequestProcessorImpl; import android.hardware.camera2.extension.IRequestUpdateProcessorImpl; @@ -90,6 +91,7 @@ import androidx.camera.extensions.impl.NightPreviewExtenderImpl; import androidx.camera.extensions.impl.PreviewExtenderImpl; import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType; import androidx.camera.extensions.impl.PreviewImageProcessorImpl; +import androidx.camera.extensions.impl.ProcessResultImpl; import androidx.camera.extensions.impl.RequestUpdateProcessorImpl; import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl; import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl; @@ -124,14 +126,17 @@ public class CameraExtensionsProxyService extends Service { private static final String LATEST_VERSION = "1.2.0"; private static final String NON_INIT_VERSION_PREFIX = "1.0"; private static final String ADVANCED_VERSION_PREFIX = "1.2"; - private static final String[] SUPPORTED_VERSION_PREFIXES = {ADVANCED_VERSION_PREFIX, - "1.1", NON_INIT_VERSION_PREFIX}; + private static final String RESULTS_VERSION_PREFIX = "1.3"; + private static final String[] SUPPORTED_VERSION_PREFIXES = {RESULTS_VERSION_PREFIX, + ADVANCED_VERSION_PREFIX, "1.1", NON_INIT_VERSION_PREFIX}; private static final boolean EXTENSIONS_PRESENT = checkForExtensions(); private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ? (new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null; private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI(); private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT && (!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX)); + private static final boolean RESULT_API_SUPPORTED = EXTENSIONS_PRESENT && + (EXTENSIONS_VERSION.startsWith(RESULTS_VERSION_PREFIX)); private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>(); private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>(); @@ -1242,7 +1247,7 @@ public class CameraExtensionsProxyService extends Service { } if (processor != null) { - return new PreviewImageProcessorImplStub(processor); + return new PreviewImageProcessorImplStub(processor, mCameraId); } return null; @@ -1332,7 +1337,7 @@ public class CameraExtensionsProxyService extends Service { public ICaptureProcessorImpl getCaptureProcessor() { CaptureProcessorImpl captureProcessor = mImageExtender.getCaptureProcessor(); if (captureProcessor != null) { - return new CaptureProcessorImplStub(captureProcessor); + return new CaptureProcessorImplStub(captureProcessor, mCameraId); } return null; @@ -1390,13 +1395,97 @@ public class CameraExtensionsProxyService extends Service { return null; } + + @Override + public CameraMetadataNative getAvailableCaptureRequestKeys() { + if (RESULT_API_SUPPORTED) { + List<CaptureRequest.Key> supportedCaptureKeys = + mImageExtender.getAvailableCaptureRequestKeys(); + + if ((supportedCaptureKeys != null) && !supportedCaptureKeys.isEmpty()) { + CameraMetadataNative ret = new CameraMetadataNative(); + long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ? + mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE; + ret.setVendorId(vendorId); + int requestKeyTags [] = new int[supportedCaptureKeys.size()]; + int i = 0; + for (CaptureRequest.Key key : supportedCaptureKeys) { + requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId); + } + ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags); + + return ret; + } + } + + return null; + } + + @Override + public CameraMetadataNative getAvailableCaptureResultKeys() { + if (RESULT_API_SUPPORTED) { + List<CaptureResult.Key> supportedResultKeys = + mImageExtender.getAvailableCaptureResultKeys(); + + if ((supportedResultKeys != null) && !supportedResultKeys.isEmpty()) { + CameraMetadataNative ret = new CameraMetadataNative(); + long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ? + mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE; + ret.setVendorId(vendorId); + int resultKeyTags [] = new int[supportedResultKeys.size()]; + int i = 0; + for (CaptureResult.Key key : supportedResultKeys) { + resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId); + } + ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags); + + return ret; + } + } + + return null; + } + } + + private class ProcessResultCallback implements ProcessResultImpl { + private final IProcessResultImpl mProcessResult; + private final String mCameraId; + + private ProcessResultCallback(IProcessResultImpl processResult, String cameraId) { + mProcessResult = processResult; + mCameraId = cameraId; + } + + @Override + public void onCaptureCompleted(long shutterTimestamp, + List<Pair<CaptureResult.Key, Object>> result) { + if (result == null) { + Log.e(TAG, "Invalid capture result received!"); + } + + CameraMetadataNative captureResults = new CameraMetadataNative(); + if (mMetadataVendorIdMap.containsKey(mCameraId)) { + captureResults.setVendorId(mMetadataVendorIdMap.get(mCameraId)); + } + for (Pair<CaptureResult.Key, Object> pair : result) { + captureResults.set(pair.first, pair.second); + } + + try { + mProcessResult.onCaptureCompleted(shutterTimestamp, captureResults); + } catch (RemoteException e) { + Log.e(TAG, "Remote client doesn't respond to capture results!"); + } + } } private class CaptureProcessorImplStub extends ICaptureProcessorImpl.Stub { private final CaptureProcessorImpl mCaptureProcessor; + private final String mCameraId; - public CaptureProcessorImplStub(CaptureProcessorImpl captureProcessor) { + public CaptureProcessorImplStub(CaptureProcessorImpl captureProcessor, String cameraId) { mCaptureProcessor = captureProcessor; + mCameraId = cameraId; } @Override @@ -1415,7 +1504,7 @@ public class CameraExtensionsProxyService extends Service { } @Override - public void process(List<CaptureBundle> captureList) { + public void process(List<CaptureBundle> captureList, IProcessResultImpl resultCallback) { HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap = new HashMap<>(); for (CaptureBundle captureBundle : captureList) { captureMap.put(captureBundle.stage, new Pair<> ( @@ -1424,7 +1513,14 @@ public class CameraExtensionsProxyService extends Service { captureBundle.sequenceId))); } if (!captureMap.isEmpty()) { - mCaptureProcessor.process(captureMap); + if ((resultCallback != null) && (RESULT_API_SUPPORTED)) { + mCaptureProcessor.process(captureMap, new ProcessResultCallback(resultCallback, + mCameraId), null /*executor*/); + } else if (resultCallback == null) { + mCaptureProcessor.process(captureMap); + } else { + Log.e(TAG, "Process requests with capture results are not supported!"); + } } else { Log.e(TAG, "Process request with absent capture stages!"); } @@ -1433,9 +1529,11 @@ public class CameraExtensionsProxyService extends Service { private class PreviewImageProcessorImplStub extends IPreviewImageProcessorImpl.Stub { private final PreviewImageProcessorImpl mProcessor; + private final String mCameraId; - public PreviewImageProcessorImplStub(PreviewImageProcessorImpl processor) { + public PreviewImageProcessorImplStub(PreviewImageProcessorImpl processor, String cameraId) { mProcessor = processor; + mCameraId = cameraId; } @Override @@ -1455,9 +1553,17 @@ public class CameraExtensionsProxyService extends Service { @Override public void process(android.hardware.camera2.extension.ParcelImage image, - CameraMetadataNative result, int sequenceId) { - mProcessor.process(new ExtensionImage(image), - new TotalCaptureResult(result, sequenceId)); + CameraMetadataNative result, int sequenceId, IProcessResultImpl resultCallback) { + if ((resultCallback != null) && RESULT_API_SUPPORTED) { + mProcessor.process(new ExtensionImage(image), + new TotalCaptureResult(result, sequenceId), + new ProcessResultCallback(resultCallback, mCameraId), null /*executor*/); + } else if (resultCallback == null) { + mProcessor.process(new ExtensionImage(image), + new TotalCaptureResult(result, sequenceId)); + } else { + + } } } diff --git a/proto/src/camera.proto b/proto/src/camera.proto index 0338b93c8842..2d62f32d3941 100644 --- a/proto/src/camera.proto +++ b/proto/src/camera.proto @@ -65,4 +65,6 @@ message CameraStreamProto { // The dynamic range profile of the stream optional int32 dynamic_range_profile = 14; + // The stream use case + optional int32 stream_use_case = 15; } diff --git a/services/Android.bp b/services/Android.bp index b0a5c66b53dd..cb042e88c104 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -183,10 +183,6 @@ cc_library_shared { name: "libandroid_servers", defaults: ["libservices.core-libs"], whole_static_libs: ["libservices.core"], - required: [ - // TODO: remove after NetworkStatsService is moved to the mainline module. - "libcom_android_net_module_util_jni", - ], } platform_compat_config { diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index c3ab2a79e288..cef0e83f6006 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -35,10 +35,10 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainRunna import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice; -import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageAssociationsForPackage; import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageCompanionDevice; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; +import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId; import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation; import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation; @@ -459,7 +459,7 @@ public class CompanionDeviceManagerService extends SystemService @Override public List<AssociationInfo> getAllAssociationsForUser(int userId) throws RemoteException { - enforceCallerCanInteractWithUserId(getContext(), userId); + enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); enforceCallerCanManageCompanionDevice(getContext(), "getAllAssociationsForUser"); return mAssociationStore.getAssociationsForUser(userId); @@ -468,7 +468,7 @@ public class CompanionDeviceManagerService extends SystemService @Override public void addOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId) { - enforceCallerCanInteractWithUserId(getContext(), userId); + enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); enforceCallerCanManageCompanionDevice(getContext(), "addOnAssociationsChangedListener"); @@ -478,7 +478,7 @@ public class CompanionDeviceManagerService extends SystemService @Override public void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId) { - enforceCallerCanInteractWithUserId(getContext(), userId); + enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); enforceCallerCanManageCompanionDevice( getContext(), "removeOnAssociationsChangedListener"); diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java index 7ebe33ea66b1..0e593e14a037 100644 --- a/services/companion/java/com/android/server/companion/PermissionsUtils.java +++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java @@ -114,6 +114,12 @@ final class PermissionsUtils { context.enforceCallingPermission(INTERACT_ACROSS_USERS, null); } + static void enforceCallerIsSystemOrCanInteractWithUserId(@NonNull Context context, int userId) { + if (getCallingUid() == SYSTEM_UID) return; + + enforceCallerCanInteractWithUserId(context, userId); + } + static boolean checkCallerIsSystemOr(@UserIdInt int userId, @NonNull String packageName) { final int callingUid = getCallingUid(); if (callingUid == SYSTEM_UID) return true; diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index 48f5b51a8404..a0575cf6bab9 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -484,7 +484,9 @@ public class BootReceiver extends BroadcastReceiver { HashMap<String, Long> timestamps = readTimestamps(); try { if (proto) { - db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0); + if (recordFileTimestamp(tombstone, timestamps)) { + db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0); + } } else { final String headers = getBootHeadersToLogAndUpdate(); addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE, @@ -526,16 +528,10 @@ public class BootReceiver extends BroadcastReceiver { if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled File file = new File(filename); - long fileTime = file.lastModified(); - if (fileTime <= 0) return; // File does not exist - - if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) { - return; // Already logged this particular file + if (!recordFileTimestamp(file, timestamps)) { + return; } - timestamps.put(filename, fileTime); - - String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); String text = headers + fileContents + footers; // Create an additional report for system server native crashes, with a special tag. @@ -548,6 +544,19 @@ public class BootReceiver extends BroadcastReceiver { addTextToDropBox(db, tag, text, filename, maxSize); } + private static boolean recordFileTimestamp(File file, HashMap<String, Long> timestamps) { + final long fileTime = file.lastModified(); + if (fileTime <= 0) return false; // File does not exist + + final String filename = file.getPath(); + if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) { + return false; // Already logged this particular file + } + + timestamps.put(filename, fileTime); + return true; + } + private static void addTextToDropBox(DropBoxManager db, String tag, String text, String filename, int maxSize) { Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")"); diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index 2845fbfc6ebf..6667d1b45027 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -311,14 +311,15 @@ public class AdbService extends IAdbManager.Stub { } /** - * @return true if the device supports secure ADB over Wi-Fi. + * @return true if the device supports secure ADB over Wi-Fi or Ethernet. * @hide */ @Override public boolean isAdbWifiSupported() { mContext.enforceCallingPermission( android.Manifest.permission.MANAGE_DEBUGGING, "AdbService"); - return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI); + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) || + mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_ETHERNET); } /** diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index bcb1be39d1b1..940ad73eee98 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -123,6 +123,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle"; static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME = "kill_bg_restricted_cached_idle_settle_time"; + static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias"; static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; @@ -199,6 +200,7 @@ final class ActivityManagerConstants extends ContentObserver { * Whether or not to enable the extra delays to service restarts on memory pressure. */ private static final boolean DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = true; + private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false; private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = ""; // Flag stored in the DeviceConfig API. @@ -595,6 +597,12 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE; /** + * Whether to enable "component alias" experimental feature. This can only be enabled + * on userdebug or eng builds. + */ + volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS; + + /** * Defines component aliases. Format * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )* */ @@ -831,6 +839,7 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE: updateEnableExtraServiceRestartDelayOnMemPressure(); break; + case KEY_ENABLE_COMPONENT_ALIAS: case KEY_COMPONENT_ALIAS_OVERRIDES: updateComponentAliases(); break; @@ -1269,11 +1278,15 @@ final class ActivityManagerConstants extends ContentObserver { } private void updateComponentAliases() { + mEnableComponentAlias = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_ENABLE_COMPONENT_ALIAS, + DEFAULT_ENABLE_COMPONENT_ALIAS); mComponentAliasOverrides = DeviceConfig.getString( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPONENT_ALIAS_OVERRIDES, DEFAULT_COMPONENT_ALIAS_OVERRIDES); - mService.mComponentAliasResolver.update(mComponentAliasOverrides); + mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides); } private void updateProcessKillTimeout() { @@ -1512,6 +1525,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mPushMessagingOverQuotaBehavior); pw.print(" "); pw.print(KEY_FGS_ALLOW_OPT_OUT); pw.print("="); pw.println(mFgsAllowOptOut); + pw.print(" "); pw.print(KEY_ENABLE_COMPONENT_ALIAS); + pw.print("="); pw.println(mEnableComponentAlias); pw.print(" "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES); pw.print("="); pw.println(mComponentAliasOverrides); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e2204e2efaca..0310b0fc4469 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8066,7 +8066,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Load the component aliases. t.traceBegin("componentAlias"); - mComponentAliasResolver.onSystemReady(mConstants.mComponentAliasOverrides); + mComponentAliasResolver.onSystemReady(mConstants.mEnableComponentAlias, + mConstants.mComponentAliasOverrides); t.traceEnd(); // componentAlias t.traceEnd(); // PhaseActivityManagerReady diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java index 23553a7cf12a..aef7a6c77b6f 100644 --- a/services/core/java/com/android/server/am/ComponentAliasResolver.java +++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Binder; +import android.os.Build; import android.os.ServiceManager; import android.os.UserHandle; import android.text.TextUtils; @@ -56,6 +57,8 @@ import java.util.function.Supplier; * "quick & dirty". For example, to define aliases, we use a regular intent filter and meta-data * in the manifest, instead of adding proper tags/attributes to AndroidManifest.xml. * + * Because it's an experimental feature, it can't be enabled on a user build. + * * Also, for now, aliases can be defined across any packages, but in the final version, there'll * be restrictions: * - We probably should only allow either privileged or preinstalled apps. @@ -78,6 +81,9 @@ public class ComponentAliasResolver { private final Context mContext; @GuardedBy("mLock") + private boolean mEnabledByDeviceConfig; + + @GuardedBy("mLock") private boolean mEnabled; @GuardedBy("mLock") @@ -141,7 +147,7 @@ public class ComponentAliasResolver { /** * Call this on systemRead(). */ - public void onSystemReady(String overrides) { + public void onSystemReady(boolean enabledByDeviceConfig, String overrides) { synchronized (mLock) { mPlatformCompat = (PlatformCompat) ServiceManager.getService( Context.PLATFORM_COMPAT_SERVICE); @@ -149,19 +155,21 @@ public class ComponentAliasResolver { mCompatChangeListener); } if (DEBUG) Slog.d(TAG, "Compat listener set."); - update(overrides); + update(enabledByDeviceConfig, overrides); } /** * (Re-)loads aliases from <meta-data> and the device config override. */ - public void update(String overrides) { + public void update(boolean enabledByDeviceConfig, String overrides) { synchronized (mLock) { if (mPlatformCompat == null) { return; // System not ready. } - final boolean enabled = mPlatformCompat.isChangeEnabledByPackageName( - USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM); + final boolean enabled = Build.isDebuggable() + && (enabledByDeviceConfig + || mPlatformCompat.isChangeEnabledByPackageName( + USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM)); if (enabled != mEnabled) { Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases..."); if (enabled) { @@ -172,6 +180,7 @@ public class ComponentAliasResolver { } } mEnabled = enabled; + mEnabledByDeviceConfig = enabledByDeviceConfig; mOverrideString = overrides; if (mEnabled) { @@ -184,7 +193,7 @@ public class ComponentAliasResolver { private void refresh() { synchronized (mLock) { - update(mOverrideString); + update(mEnabledByDeviceConfig, mOverrideString); } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index e4c0846d090f..481b6dddc31b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -2034,6 +2034,11 @@ class UserController implements Handler.Callback { } } + /** + * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is + * likely a lot going on, and WM won't unfreeze until the drawing is all done, so + * the actual unfreeze may still not happen for a long time; this is expected. + */ @VisibleForTesting void unfreezeScreen() { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java index 145a298af95e..4eba77168b8e 100644 --- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java +++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java @@ -473,7 +473,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan } try { - mWindowManagerInternal.addTaskOverlay( + mWindowManagerInternal.addTrustedTaskOverlay( taskId, createGameSessionResult.getSurfacePackage()); } catch (IllegalArgumentException ex) { @@ -519,7 +519,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan SurfacePackage surfacePackage = gameSessionRecord.getSurfacePackage(); if (surfacePackage != null) { try { - mWindowManagerInternal.removeTaskOverlay( + mWindowManagerInternal.removeTrustedTaskOverlay( gameSessionRecord.getTaskId(), surfacePackage); } catch (IllegalArgumentException ex) { diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java index 366718c65d84..aa0d3da6a94f 100644 --- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -35,6 +35,8 @@ import android.app.ActivityThread; import android.app.IActivityManager; import android.app.StatsManager; import android.app.StatsManager.StatsPullAtomCallback; +import android.app.usage.StorageStats; +import android.app.usage.StorageStatsManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.UsageEventListener; @@ -78,6 +80,7 @@ import com.android.server.SystemService; import java.io.File; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -111,6 +114,7 @@ public final class AppHibernationService extends SystemService { private final PackageManagerInternal mPackageManagerInternal; private final IActivityManager mIActivityManager; private final UserManager mUserManager; + private final StorageStatsManager mStorageStatsManager; @GuardedBy("mLock") private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>(); @@ -147,6 +151,7 @@ public final class AppHibernationService extends SystemService { mPackageManagerInternal = injector.getPackageManagerInternal(); mIActivityManager = injector.getActivityManager(); mUserManager = injector.getUserManager(); + mStorageStatsManager = injector.getStorageStatsManager(); mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore(); mBackgroundExecutor = injector.getBackgroundExecutor(); mOatArtifactDeletionEnabled = injector.isOatArtifactDeletionEnabled(); @@ -217,7 +222,7 @@ public final class AppHibernationService extends SystemService { */ boolean isHibernatingForUser(String packageName, int userId) { String methodName = "isHibernatingForUser"; - if (!checkHibernationEnabled(methodName)) { + if (!sIsServiceEnabled) { return false; } getContext().enforceCallingOrSelfPermission( @@ -246,7 +251,7 @@ public final class AppHibernationService extends SystemService { * @param packageName package to check */ boolean isHibernatingGlobally(String packageName) { - if (!checkHibernationEnabled("isHibernatingGlobally")) { + if (!sIsServiceEnabled) { return false; } getContext().enforceCallingOrSelfPermission( @@ -272,7 +277,7 @@ public final class AppHibernationService extends SystemService { */ void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { String methodName = "setHibernatingForUser"; - if (!checkHibernationEnabled(methodName)) { + if (!sIsServiceEnabled) { return; } getContext().enforceCallingOrSelfPermission( @@ -297,7 +302,8 @@ public final class AppHibernationService extends SystemService { pkgState.hibernated = isHibernating; if (isHibernating) { - mBackgroundExecutor.execute(() -> hibernatePackageForUser(packageName, realUserId)); + mBackgroundExecutor.execute( + () -> hibernatePackageForUser(packageName, realUserId, pkgState)); } else { mBackgroundExecutor.execute( () -> unhibernatePackageForUser(packageName, realUserId)); @@ -326,7 +332,7 @@ public final class AppHibernationService extends SystemService { * @param isHibernating new hibernation state */ void setHibernatingGlobally(String packageName, boolean isHibernating) { - if (!checkHibernationEnabled("setHibernatingGlobally")) { + if (!sIsServiceEnabled) { return; } getContext().enforceCallingOrSelfPermission( @@ -359,7 +365,7 @@ public final class AppHibernationService extends SystemService { @NonNull List<String> getHibernatingPackagesForUser(int userId) { ArrayList<String> hibernatingPackages = new ArrayList<>(); String methodName = "getHibernatingPackagesForUser"; - if (!checkHibernationEnabled(methodName)) { + if (!sIsServiceEnabled) { return hibernatingPackages; } getContext().enforceCallingOrSelfPermission( @@ -390,6 +396,9 @@ public final class AppHibernationService extends SystemService { @Nullable Set<String> packageNames, int userId) { Map<String, HibernationStats> statsMap = new ArrayMap<>(); String methodName = "getHibernationStatsForUser"; + if (!sIsServiceEnabled) { + return statsMap; + } getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_APP_HIBERNATION, "Caller does not have MANAGE_APP_HIBERNATION permission."); @@ -412,8 +421,9 @@ public final class AppHibernationService extends SystemService { + "the package was uninstalled? ", pkgName, userId)); continue; } - HibernationStats stats = new HibernationStats( - mGlobalHibernationStates.get(pkgName).savedByte); + long diskBytesSaved = mGlobalHibernationStates.get(pkgName).savedByte + + userPackageStates.get(pkgName).savedByte; + HibernationStats stats = new HibernationStats(diskBytesSaved); statsMap.put(pkgName, stats); } } @@ -424,16 +434,28 @@ public final class AppHibernationService extends SystemService { * Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do * not hold {@link #mLock} while calling this to avoid deadlock scenarios. */ - private void hibernatePackageForUser(@NonNull String packageName, int userId) { + private void hibernatePackageForUser(@NonNull String packageName, int userId, + UserLevelState state) { Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage"); final long caller = Binder.clearCallingIdentity(); try { + ApplicationInfo info = mIPackageManager.getApplicationInfo( + packageName, PACKAGE_MATCH_FLAGS, userId); + StorageStats stats = mStorageStatsManager.queryStatsForPackage( + info.storageUuid, packageName, new UserHandle(userId)); mIActivityManager.forceStopPackage(packageName, userId); mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId, null /* observer */); + synchronized (mLock) { + state.savedByte = stats.getCacheBytes(); + } } catch (RemoteException e) { throw new IllegalStateException( "Failed to hibernate due to manager not being available", e); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Package name not found when querying storage stats", e); + } catch (IOException e) { + Slog.e(TAG, "Storage device not found", e); } finally { Binder.restoreCallingIdentity(caller); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); @@ -677,6 +699,7 @@ public final class AppHibernationService extends SystemService { for (String key : properties.getKeyset()) { if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) { sIsServiceEnabled = isDeviceConfigAppHibernationEnabled(); + Slog.d(TAG, "App hibernation changed to enabled=" + sIsServiceEnabled); break; } } @@ -721,13 +744,6 @@ public final class AppHibernationService extends SystemService { return true; } - private boolean checkHibernationEnabled(String methodName) { - if (!sIsServiceEnabled) { - Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName)); - } - return sIsServiceEnabled; - } - private void dump(PrintWriter pw) { // Check usage stats permission since hibernation indirectly informs usage. if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; @@ -923,6 +939,8 @@ public final class AppHibernationService extends SystemService { UserManager getUserManager(); + StorageStatsManager getStorageStatsManager(); + Executor getBackgroundExecutor(); UsageStatsManagerInternal getUsageStatsManagerInternal(); @@ -972,6 +990,11 @@ public final class AppHibernationService extends SystemService { } @Override + public StorageStatsManager getStorageStatsManager() { + return mContext.getSystemService(StorageStatsManager.class); + } + + @Override public Executor getBackgroundExecutor() { return mScheduledExecutorService; } diff --git a/services/core/java/com/android/server/apphibernation/UserLevelState.java b/services/core/java/com/android/server/apphibernation/UserLevelState.java index 68c363c8256a..6a489d28ac17 100644 --- a/services/core/java/com/android/server/apphibernation/UserLevelState.java +++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java @@ -28,6 +28,8 @@ final class UserLevelState { public String packageName; public boolean hibernated; + // Saved bytes from user level hibernation. + public long savedByte; @CurrentTimeMillisLong public long lastUnhibernatedMs; @@ -36,6 +38,7 @@ final class UserLevelState { UserLevelState(UserLevelState state) { packageName = state.packageName; hibernated = state.hibernated; + savedByte = state.savedByte; lastUnhibernatedMs = state.lastUnhibernatedMs; } @@ -44,6 +47,7 @@ final class UserLevelState { return "UserLevelState{" + "packageName='" + packageName + '\'' + ", hibernated=" + hibernated + '\'' + + ", savedByte=" + savedByte + '\'' + ", lastUnhibernated=" + DATE_FORMAT.format(lastUnhibernatedMs) + '}'; } diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 1b0341c1ce26..e0b768d7c592 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -808,6 +808,7 @@ public class CameraServiceProxy extends SystemService streamProtos[i].histogramBins = streamStats.getHistogramBins(); streamProtos[i].histogramCounts = streamStats.getHistogramCounts(); streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile(); + streamProtos[i].streamUseCase = streamStats.getStreamUseCase(); if (CameraServiceProxy.DEBUG) { String histogramTypeName = @@ -828,7 +829,8 @@ public class CameraServiceProxy extends SystemService + Arrays.toString(streamProtos[i].histogramBins) + ", histogramCounts " + Arrays.toString(streamProtos[i].histogramCounts) - + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile); + + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile + + ", streamUseCase " + streamProtos[i].streamUseCase); } } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 354d1838709d..94c694d39df7 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -305,7 +305,8 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken); private static native void nativePilferPointers(long ptr, IBinder token); private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); - private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode); + private static native boolean nativeSetInTouchMode(long ptr, boolean inTouchMode, int pid, + int uid, boolean hasPermission); private static native void nativeSetMaximumObscuringOpacityForTouch(long ptr, float opacity); private static native void nativeSetBlockUntrustedTouchesMode(long ptr, int mode); private static native int nativeInjectInputEvent(long ptr, InputEvent event, @@ -866,12 +867,16 @@ public class InputManagerService extends IInputManager.Stub * other apps, when they become focused. * * When input dispatches focus to the apps, the touch mode state - * will be sent together with the focus change. + * will be sent together with the focus change (but each one in its own event). * - * @param inTouchMode true if the device is in touch mode. + * @param inTouchMode true if the device is in touch mode + * @param pid the pid of the process that requested to switch touch mode state + * @param uid the uid of the process that requested to switch touch mode state + * @param hasPermission if set to {@code true} then no further authorization will be performed + * @return {@code true} if the touch mode was successfully changed, {@code false} otherwise */ - public void setInTouchMode(boolean inTouchMode) { - nativeSetInTouchMode(mPtr, inTouchMode); + public boolean setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission) { + return nativeSetInTouchMode(mPtr, inTouchMode, pid, uid, hasPermission); } @Override // Binder call diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c207738a4f88..ba15a047af4a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1495,8 +1495,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onStart() { - LocalServices.addService(InputMethodManagerInternal.class, - new LocalServiceImpl(mService)); + mService.publishLocalService(); publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO); } @@ -4866,26 +4865,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return mCurrentSubtype; } - private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { - synchronized (ImfLock.class) { - return getInputMethodListLocked(userId, DirectBootAwareness.AUTO); - } - } - - private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) { - synchronized (ImfLock.class) { - return getEnabledInputMethodListLocked(userId); - } - } - - private void onCreateInlineSuggestionsRequest(@UserIdInt int userId, - InlineSuggestionsRequestInfo requestInfo, - IInlineSuggestionsRequestCallback callback) { - synchronized (ImfLock.class) { - onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback); - } - } - private ArrayMap<String, InputMethodInfo> queryMethodMapForUser(@UserIdInt int userId) { final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>(); final ArrayList<InputMethodInfo> methodList = new ArrayList<>(); @@ -4897,161 +4876,153 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return methodMap; } - private boolean switchToInputMethod(String imeId, @UserIdInt int userId) { - synchronized (ImfLock.class) { - if (userId == mSettings.getCurrentUserId()) { - if (!mMethodMap.containsKey(imeId) - || !mSettings.getEnabledInputMethodListLocked() - .contains(mMethodMap.get(imeId))) { - return false; // IME is not found or not enabled. - } - setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID); - return true; - } - final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings( - mContext.getResources(), mContext.getContentResolver(), methodMap, - userId, false); - if (!methodMap.containsKey(imeId) - || !settings.getEnabledInputMethodListLocked() - .contains(methodMap.get(imeId))) { + @GuardedBy("ImfLock.class") + private boolean switchToInputMethodLocked(String imeId, @UserIdInt int userId) { + if (userId == mSettings.getCurrentUserId()) { + if (!mMethodMap.containsKey(imeId) + || !mSettings.getEnabledInputMethodListLocked() + .contains(mMethodMap.get(imeId))) { return false; // IME is not found or not enabled. } - settings.putSelectedInputMethod(imeId); - settings.putSelectedSubtype(NOT_A_SUBTYPE_ID); - return true; - } - } - - private boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) { - synchronized (ImfLock.class) { - if (userId == mSettings.getCurrentUserId()) { - if (!mMethodMap.containsKey(imeId)) { - return false; // IME is not found. - } - setInputMethodEnabledLocked(imeId, enabled); - return true; - } - final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings( - mContext.getResources(), mContext.getContentResolver(), methodMap, - userId, false); - if (!methodMap.containsKey(imeId)) { - return false; // IME is not found. - } - if (enabled) { - if (!settings.getEnabledInputMethodListLocked().contains(methodMap.get(imeId))) { - settings.appendAndPutEnabledInputMethodLocked(imeId, false); - } - } else { - settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked( - new StringBuilder(), - settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId); - } + setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID); return true; } + final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); + final InputMethodSettings settings = new InputMethodSettings( + mContext.getResources(), mContext.getContentResolver(), methodMap, + userId, false); + if (!methodMap.containsKey(imeId) + || !settings.getEnabledInputMethodListLocked() + .contains(methodMap.get(imeId))) { + return false; // IME is not found or not enabled. + } + settings.putSelectedInputMethod(imeId); + settings.putSelectedSubtype(NOT_A_SUBTYPE_ID); + return true; } - private boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken, - int displayId) { - //TODO(b/150843766): Check if Input Token is valid. - final IBinder curHostInputToken; - synchronized (ImfLock.class) { - if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) { - return false; - } - curHostInputToken = mCurHostInputToken; - } - return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken); - } - - private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { - synchronized (ImfLock.class) { - if (mCurFocusedWindow != windowToken) { - // mCurPerceptible was set by the focused window, but it is no longer in control, - // so we reset mCurPerceptible. - mCurPerceptible = true; - } - if (imeParentChanged) { - // Hide the IME method menu earlier when the IME surface parent will change in - // case seeing the dialog dismiss flickering during the next focused window - // starting the input connection. - mMenuController.hideInputMethodMenu(); - } - } + private void publishLocalService() { + LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl()); } - private static final class LocalServiceImpl extends InputMethodManagerInternal { - @NonNull - private final InputMethodManagerService mService; - - LocalServiceImpl(@NonNull InputMethodManagerService service) { - mService = service; - } + private final class LocalServiceImpl extends InputMethodManagerInternal { @Override public void setInteractive(boolean interactive) { // Do everything in handler so as not to block the caller. - mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0) - .sendToTarget(); + mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0).sendToTarget(); } @Override public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { - mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); - mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget(); + mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); + mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget(); } @Override public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { - return mService.getInputMethodListAsUser(userId); + synchronized (ImfLock.class) { + return getInputMethodListLocked(userId, DirectBootAwareness.AUTO); + } } @Override public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) { - return mService.getEnabledInputMethodListAsUser(userId); + synchronized (ImfLock.class) { + return getEnabledInputMethodListLocked(userId); + } } @Override public void onCreateInlineSuggestionsRequest(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) { - mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb); + synchronized (ImfLock.class) { + onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb); + } } @Override public boolean switchToInputMethod(String imeId, @UserIdInt int userId) { - return mService.switchToInputMethod(imeId, userId); + synchronized (ImfLock.class) { + return switchToInputMethodLocked(imeId, userId); + } } @Override public boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) { - return mService.setInputMethodEnabled(imeId, enabled, userId); + synchronized (ImfLock.class) { + if (userId == mSettings.getCurrentUserId()) { + if (!mMethodMap.containsKey(imeId)) { + return false; // IME is not found. + } + setInputMethodEnabledLocked(imeId, enabled); + return true; + } + final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); + final InputMethodSettings settings = new InputMethodSettings( + mContext.getResources(), mContext.getContentResolver(), methodMap, + userId, false); + if (!methodMap.containsKey(imeId)) { + return false; // IME is not found. + } + if (enabled) { + if (!settings.getEnabledInputMethodListLocked().contains( + methodMap.get(imeId))) { + settings.appendAndPutEnabledInputMethodLocked(imeId, false); + } + } else { + settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked( + new StringBuilder(), + settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId); + } + return true; + } } @Override public void registerInputMethodListListener(InputMethodListListener listener) { - mService.mInputMethodListListeners.addIfAbsent(listener); + mInputMethodListListeners.addIfAbsent(listener); } @Override public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken, int displayId) { - return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId); + //TODO(b/150843766): Check if Input Token is valid. + final IBinder curHostInputToken; + synchronized (ImfLock.class) { + if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) { + return false; + } + curHostInputToken = mCurHostInputToken; + } + return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken); } @Override public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { - mService.reportImeControl(windowToken, imeParentChanged); + synchronized (ImfLock.class) { + if (mCurFocusedWindow != windowToken) { + // mCurPerceptible was set by the focused window, but it is no longer in + // control, so we reset mCurPerceptible. + mCurPerceptible = true; + } + if (imeParentChanged) { + // Hide the IME method menu earlier when the IME surface parent will change in + // case seeing the dialog dismiss flickering during the next focused window + // starting the input connection. + mMenuController.hideInputMethodMenu(); + } + } } @Override public void removeImeSurface() { - mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget(); + mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget(); } @Override public void updateImeWindowStatus(boolean disableImeIcon) { - mService.mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0) + mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0) .sendToTarget(); } } @@ -5689,7 +5660,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (!userHasDebugPriv(userId, shellCommand)) { continue; } - boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId); + boolean failedToSelectUnknownIme = !switchToInputMethodLocked(imeId, userId); if (failedToSelectUnknownIme) { error.print("Unknown input method "); error.print(imeId); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 8ce67a657740..76d06c8801f4 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -119,9 +119,7 @@ import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; -import static com.android.internal.util.XmlUtils.readThisIntArrayXml; import static com.android.internal.util.XmlUtils.writeBooleanAttribute; -import static com.android.internal.util.XmlUtils.writeIntArrayXml; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; @@ -246,7 +244,6 @@ import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.StatLogger; -import com.android.internal.util.XmlUtils; import com.android.net.module.util.NetworkIdentityUtils; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; @@ -260,8 +257,6 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; import libcore.io.IoUtils; -import org.xmlpull.v1.XmlPullParserException; - import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -336,7 +331,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int VERSION_ADDED_CYCLE = 11; private static final int VERSION_ADDED_NETWORK_TYPES = 12; private static final int VERSION_SUPPORTED_CARRIER_USAGE = 13; - private static final int VERSION_LATEST = VERSION_SUPPORTED_CARRIER_USAGE; + private static final int VERSION_REMOVED_SUBSCRIPTION_PLANS = 14; + private static final int VERSION_LATEST = VERSION_REMOVED_SUBSCRIPTION_PLANS; @VisibleForTesting public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING; @@ -349,7 +345,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String TAG_POLICY_LIST = "policy-list"; private static final String TAG_NETWORK_POLICY = "network-policy"; - private static final String TAG_SUBSCRIPTION_PLAN = "subscription-plan"; private static final String TAG_UID_POLICY = "uid-policy"; private static final String TAG_APP_POLICY = "app-policy"; private static final String TAG_WHITELIST = "whitelist"; @@ -426,6 +421,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * obj = oldBlockedReasons */ private static final int MSG_BLOCKED_REASON_CHANGED = 21; + /** + * Message to indicate that subscription plans expired and should be cleared. + * arg1 = subId + * arg2 = setSubscriptionPlans call ID + * obj = callingPackage + */ + private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -492,6 +494,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Map from subId to package name that owns subscription plans. */ @GuardedBy("mNetworkPoliciesSecondLock") final SparseArray<String> mSubscriptionPlansOwner = new SparseArray<>(); + /** Map from subId to the ID of the clear plans request. */ + @GuardedBy("mNetworkPoliciesSecondLock") + final SparseIntArray mSetSubscriptionPlansIds = new SparseIntArray(); + /** Atomic integer to generate a new ID for each clear plans request. */ + @GuardedBy("mNetworkPoliciesSecondLock") + int mSetSubscriptionPlansIdCounter = 0; /** Map from subId to daily opportunistic quota. */ @GuardedBy("mNetworkPoliciesSecondLock") @@ -2523,56 +2531,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred)); } - - } else if (TAG_SUBSCRIPTION_PLAN.equals(tag)) { - final String start = readStringAttribute(in, ATTR_CYCLE_START); - final String end = readStringAttribute(in, ATTR_CYCLE_END); - final String period = readStringAttribute(in, ATTR_CYCLE_PERIOD); - final SubscriptionPlan.Builder builder = new SubscriptionPlan.Builder( - RecurrenceRule.convertZonedDateTime(start), - RecurrenceRule.convertZonedDateTime(end), - RecurrenceRule.convertPeriod(period)); - builder.setTitle(readStringAttribute(in, ATTR_TITLE)); - builder.setSummary(readStringAttribute(in, ATTR_SUMMARY)); - - final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES, - SubscriptionPlan.BYTES_UNKNOWN); - final int limitBehavior = readIntAttribute(in, ATTR_LIMIT_BEHAVIOR, - SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN); - if (limitBytes != SubscriptionPlan.BYTES_UNKNOWN - && limitBehavior != SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) { - builder.setDataLimit(limitBytes, limitBehavior); - } - - final long usageBytes = readLongAttribute(in, ATTR_USAGE_BYTES, - SubscriptionPlan.BYTES_UNKNOWN); - final long usageTime = readLongAttribute(in, ATTR_USAGE_TIME, - SubscriptionPlan.TIME_UNKNOWN); - if (usageBytes != SubscriptionPlan.BYTES_UNKNOWN - && usageTime != SubscriptionPlan.TIME_UNKNOWN) { - builder.setDataUsage(usageBytes, usageTime); - } - - final int subId = readIntAttribute(in, ATTR_SUB_ID); - final String ownerPackage = readStringAttribute(in, ATTR_OWNER_PACKAGE); - - if (version >= VERSION_ADDED_NETWORK_TYPES) { - final int depth = in.getDepth(); - while (XmlUtils.nextElementWithin(in, depth)) { - if (TAG_XML_UTILS_INT_ARRAY.equals(in.getName()) - && ATTR_NETWORK_TYPES.equals( - readStringAttribute(in, ATTR_XML_UTILS_NAME))) { - final int[] networkTypes = - readThisIntArrayXml(in, TAG_XML_UTILS_INT_ARRAY, null); - builder.setNetworkTypes(networkTypes); - } - } - } - - final SubscriptionPlan plan = builder.build(); - mSubscriptionPlans.put(subId, ArrayUtils.appendElement( - SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan)); - mSubscriptionPlansOwner.put(subId, ownerPackage); } else if (TAG_UID_POLICY.equals(tag)) { final int uid = readIntAttribute(in, ATTR_UID); final int policy = readIntAttribute(in, ATTR_POLICY); @@ -2763,38 +2721,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { out.endTag(null, TAG_NETWORK_POLICY); } - // write all known subscription plans - for (int i = 0; i < mSubscriptionPlans.size(); i++) { - final int subId = mSubscriptionPlans.keyAt(i); - if (subId == INVALID_SUBSCRIPTION_ID) continue; - final String ownerPackage = mSubscriptionPlansOwner.get(subId); - final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i); - if (ArrayUtils.isEmpty(plans)) continue; - - for (SubscriptionPlan plan : plans) { - out.startTag(null, TAG_SUBSCRIPTION_PLAN); - writeIntAttribute(out, ATTR_SUB_ID, subId); - writeStringAttribute(out, ATTR_OWNER_PACKAGE, ownerPackage); - final RecurrenceRule cycleRule = plan.getCycleRule(); - writeStringAttribute(out, ATTR_CYCLE_START, - RecurrenceRule.convertZonedDateTime(cycleRule.start)); - writeStringAttribute(out, ATTR_CYCLE_END, - RecurrenceRule.convertZonedDateTime(cycleRule.end)); - writeStringAttribute(out, ATTR_CYCLE_PERIOD, - RecurrenceRule.convertPeriod(cycleRule.period)); - writeStringAttribute(out, ATTR_TITLE, plan.getTitle()); - writeStringAttribute(out, ATTR_SUMMARY, plan.getSummary()); - writeLongAttribute(out, ATTR_LIMIT_BYTES, plan.getDataLimitBytes()); - writeIntAttribute(out, ATTR_LIMIT_BEHAVIOR, plan.getDataLimitBehavior()); - writeLongAttribute(out, ATTR_USAGE_BYTES, plan.getDataUsageBytes()); - writeLongAttribute(out, ATTR_USAGE_TIME, plan.getDataUsageTime()); - try { - writeIntArrayXml(plan.getNetworkTypes(), ATTR_NETWORK_TYPES, out); - } catch (XmlPullParserException ignored) { } - out.endTag(null, TAG_SUBSCRIPTION_PLAN); - } - } - // write all known uid policies for (int i = 0; i < mUidPolicy.size(); i++) { final int uid = mUidPolicy.keyAt(i); @@ -3668,7 +3594,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) { + public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, + long expirationDurationMillis, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); enforceSubscriptionPlanValidity(plans); @@ -3678,31 +3605,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long token = Binder.clearCallingIdentity(); try { - synchronized (mUidRulesFirstLock) { - synchronized (mNetworkPoliciesSecondLock) { - mSubscriptionPlans.put(subId, plans); - mSubscriptionPlansOwner.put(subId, callingPackage); + setSubscriptionPlansInternal(subId, plans, expirationDurationMillis, callingPackage); + } finally { + Binder.restoreCallingIdentity(token); + } + } - final String subscriberId = mSubIdToSubscriberId.get(subId, null); - if (subscriberId != null) { - ensureActiveCarrierPolicyAL(subId, subscriberId); - maybeUpdateCarrierPolicyCycleAL(subId, subscriberId); - } else { - Slog.wtf(TAG, "Missing subscriberId for subId " + subId); - } + private void setSubscriptionPlansInternal(int subId, SubscriptionPlan[] plans, + long expirationDurationMillis, String callingPackage) { + synchronized (mUidRulesFirstLock) { + synchronized (mNetworkPoliciesSecondLock) { + mSubscriptionPlans.put(subId, plans); + mSubscriptionPlansOwner.put(subId, callingPackage); - handleNetworkPoliciesUpdateAL(true); + final String subscriberId = mSubIdToSubscriberId.get(subId, null); + if (subscriberId != null) { + ensureActiveCarrierPolicyAL(subId, subscriberId); + maybeUpdateCarrierPolicyCycleAL(subId, subscriberId); + } else { + Slog.wtf(TAG, "Missing subscriberId for subId " + subId); } - } - final Intent intent = new Intent(SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); - mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS); - mHandler.sendMessage( - mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans)); - } finally { - Binder.restoreCallingIdentity(token); + handleNetworkPoliciesUpdateAL(true); + + final Intent intent = new Intent( + SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); + mContext.sendBroadcast(intent, + android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS); + mHandler.sendMessage(mHandler.obtainMessage( + MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans)); + final int setPlansId = mSetSubscriptionPlansIdCounter++; + mSetSubscriptionPlansIds.put(subId, setPlansId); + if (expirationDurationMillis > 0) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_SUBSCRIPTION_PLANS, + subId, setPlansId, callingPackage), expirationDurationMillis); + } + } } } @@ -3728,7 +3668,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, - int[] networkTypes, long timeoutMillis, String callingPackage) { + int[] networkTypes, long expirationDurationMillis, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); final ArraySet<Integer> allNetworksSet = new ArraySet<>(); @@ -3766,10 +3706,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { args.arg3 = overrideValue; args.arg4 = applicableNetworks.toArray(); mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args)); - if (timeoutMillis > 0) { + if (expirationDurationMillis > 0) { args.arg3 = 0; mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args), - timeoutMillis); + expirationDurationMillis); } } } @@ -5184,6 +5124,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_CLEAR_SUBSCRIPTION_PLANS: { + synchronized (mUidRulesFirstLock) { + synchronized (mNetworkPoliciesSecondLock) { + int subId = msg.arg1; + if (msg.arg2 == mSetSubscriptionPlansIds.get(subId)) { + if (LOGD) Slog.d(TAG, "Clearing expired subscription plans."); + setSubscriptionPlansInternal(subId, new SubscriptionPlan[]{}, + 0 /* expirationDurationMillis */, + (String) msg.obj /* callingPackage */); + } else { + if (LOGD) Slog.d(TAG, "Ignoring stale CLEAR_SUBSCRIPTION_PLANS."); + } + } + } + return true; + } case MSG_BLOCKED_REASON_CHANGED: { final int uid = msg.arg1; final int newBlockedReasons = msg.arg2; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6b27321f856f..bc38087ebc73 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2463,7 +2463,7 @@ public class NotificationManagerService extends SystemService { }; mAllowFgsDismissal = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, false); + SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, true); DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, new HandlerExecutor(mHandler), diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b07cd1063ed2..652080a3f11d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2515,13 +2515,17 @@ public class UserManagerService extends IUserManager.Stub { return 0 < getRemainingCreatableProfileCount(userType, userId, allowedToRemoveOne); } + @Override + public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId) { + return getRemainingCreatableProfileCount(userType, userId, false); + } + /** * Returns the remaining number of profiles of the given type that can be added to the given * user. (taking into account the total number of users on the device as well as how many * profiles exist of that type both in general and for the given user) */ - @Override - public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId, + private int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId, boolean allowedToRemoveOne) { checkQueryOrCreateUsersPermission( "get the remaining number of profiles that can be added to the given user."); diff --git a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java new file mode 100644 index 000000000000..750d4004cb60 --- /dev/null +++ b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java @@ -0,0 +1,125 @@ +/* + * 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.sensorprivacy; + +import android.app.AppOpsManager; +import android.content.Context; +import android.hardware.lights.Light; +import android.hardware.lights.LightState; +import android.hardware.lights.LightsManager; +import android.hardware.lights.LightsRequest; +import android.permission.PermissionManager; +import android.util.ArraySet; + +import com.android.internal.R; +import com.android.server.FgThread; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +class CameraPrivacyLightController implements AppOpsManager.OnOpActiveChangedListener { + + private final Context mContext; + private final LightsManager mLightsManager; + + private final Set<String> mActivePackages = new ArraySet<>(); + private final Set<String> mActivePhonePackages = new ArraySet<>(); + + private final int mCameraPrivacyLightColor; + + private final List<Light> mCameraLights = new ArrayList<>(); + private final AppOpsManager mAppOpsManager; + + private LightsManager.LightsSession mLightsSession = null; + + CameraPrivacyLightController(Context context) { + mContext = context; + + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); + mLightsManager = mContext.getSystemService(LightsManager.class); + + mCameraPrivacyLightColor = mContext.getColor(R.color.camera_privacy_light); + + List<Light> lights = mLightsManager.getLights(); + for (int i = 0; i < lights.size(); i++) { + Light light = lights.get(i); + if (light.getType() == Light.LIGHT_TYPE_CAMERA) { + mCameraLights.add(light); + } + } + + if (mCameraLights.isEmpty()) { + return; + } + + mAppOpsManager.startWatchingActive( + new String[] {AppOpsManager.OPSTR_CAMERA, AppOpsManager.OPSTR_PHONE_CALL_CAMERA}, + FgThread.getExecutor(), this); + } + + @Override + public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { + final Set<String> activePackages; + if (AppOpsManager.OPSTR_CAMERA.equals(op)) { + activePackages = mActivePackages; + } else if (AppOpsManager.OPSTR_PHONE_CALL_CAMERA.equals(op)) { + activePackages = mActivePhonePackages; + } else { + return; + } + + if (active) { + activePackages.add(packageName); + } else { + activePackages.remove(packageName); + } + + updateLightSession(); + } + + private void updateLightSession() { + Set<String> exemptedPackages = PermissionManager.getIndicatorExemptedPackages(mContext); + + boolean shouldSessionEnd = exemptedPackages.containsAll(mActivePackages) + && exemptedPackages.containsAll(mActivePhonePackages); + + if (shouldSessionEnd) { + if (mLightsSession == null) { + return; + } + + mLightsSession.close(); + mLightsSession = null; + } else { + if (mLightsSession != null) { + return; + } + + LightsRequest.Builder requestBuilder = new LightsRequest.Builder(); + for (int i = 0; i < mCameraLights.size(); i++) { + requestBuilder.addLight(mCameraLights.get(i), + new LightState.Builder() + .setColor(mCameraPrivacyLightColor) + .build()); + } + + mLightsSession = mLightsManager.openSession(Integer.MAX_VALUE); + mLightsSession.requestLights(requestBuilder.build()); + } + } +} diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java index e9b5f1156d39..040fffa885f1 100644 --- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java +++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java @@ -154,6 +154,8 @@ public final class SensorPrivacyService extends SystemService { private final AppOpsManagerInternal mAppOpsManagerInternal; private final TelephonyManager mTelephonyManager; + private CameraPrivacyLightController mCameraPrivacyLightController; + private final IBinder mAppOpsRestrictionToken = new Binder(); private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal; @@ -190,6 +192,8 @@ public final class SensorPrivacyService extends SystemService { if (phase == PHASE_SYSTEM_SERVICES_READY) { mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mEmergencyCallHelper = new EmergencyCallHelper(); + } else if (phase == PHASE_ACTIVITY_MANAGER_READY) { + mCameraPrivacyLightController = new CameraPrivacyLightController(mContext); } } diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java index 21d4cbbbcca7..f4b335e42ec5 100644 --- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java +++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java @@ -365,6 +365,20 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn } @Override + public void onSegmentResults(Bundle results) throws RemoteException { + mRemoteListener.onSegmentResults(results); + } + + @Override + public void onEndOfSegmentedSession() throws RemoteException { + if (DEBUG) { + Slog.i(TAG, "#onEndOfSegmentedSession invoked for a recognition session"); + } + mOnSessionComplete.run(); + mRemoteListener.onEndOfSegmentedSession(); + } + + @Override public void onEvent(int eventType, Bundle params) throws RemoteException { mRemoteListener.onEvent(eventType, params); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index ee2cc7bd7486..56985af9ef9f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2591,8 +2591,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub */ @Override public void setWallpaperDimAmount(float dimAmount) throws RemoteException { + setWallpaperDimAmountForUid(Binder.getCallingUid(), dimAmount); + } + + /** + * Sets wallpaper dim amount for a given UID. This only applies to FLAG_SYSTEM wallpaper as the + * lock screen does not have a wallpaper component, so we use mWallpaperMap. + * + * @param uid Caller UID that wants to set the wallpaper dim amount + * @param dimAmount Dim amount where 0f reverts any dimming applied by the caller (fully bright) + * and 1f is fully black + * @throws RemoteException + */ + public void setWallpaperDimAmountForUid(int uid, float dimAmount) { checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT); - int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java index fc827b40f3a1..458bf20877f6 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java @@ -43,6 +43,8 @@ public class WallpaperManagerShellCommand extends ShellCommand { switch(cmd) { case "set-dim-amount": return setWallpaperDimAmount(); + case "dim-with-uid": + return setDimmingWithUid(); case "get-dim-amount": return getWallpaperDimAmount(); case "-h": @@ -64,6 +66,10 @@ public class WallpaperManagerShellCommand extends ShellCommand { pw.println(" set-dim-amount DIMMING"); pw.println(" Sets the current dimming value to DIMMING (a number between 0 and 1)."); pw.println(); + pw.println(" dim-with-uid UID DIMMING"); + pw.println(" Sets the wallpaper dim amount to DIMMING as if an app with uid, UID, " + + "called it."); + pw.println(); pw.println(" get-dim-amount"); pw.println(" Get the current wallpaper dim amount."); } @@ -92,4 +98,17 @@ public class WallpaperManagerShellCommand extends ShellCommand { getOutPrintWriter().println("The current wallpaper dim amount is: " + dimAmount); return 0; } + + /** + * Sets the wallpaper dim amount for an arbitrary UID to simulate multiple applications setting + * a dim amount on the wallpaper. + */ + private int setDimmingWithUid() { + int mockUid = Integer.parseInt(getNextArgRequired()); + float mockDimAmount = Float.parseFloat(getNextArgRequired()); + mService.setWallpaperDimAmountForUid(mockUid, mockDimAmount); + getOutPrintWriter().println("Dimming the wallpaper for UID: " + mockUid + " to: " + + mockDimAmount); + return 0; + } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index ad4594873cf0..155db2c58654 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1082,6 +1082,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe for (WindowContainer<?> p = wc.getParent(); p != null; p = p.getParent()) { final ChangeInfo parentChange = changes.get(p); if (parentChange == null || !parentChange.hasChanged(p)) break; + if (p.mRemoteToken == null) { + // Intermediate parents must be those that has window to be managed by Shell. + continue; + } if (parentChange.mParent != null && !skipIntermediateReports) { changes.get(wc).mParent = p; // The chain above the parent was processed. diff --git a/services/core/java/com/android/server/wm/OverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java index 90f5b09968ea..975b21c6f02c 100644 --- a/services/core/java/com/android/server/wm/OverlayHost.java +++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java @@ -32,14 +32,20 @@ import java.util.ArrayList; * * Also handles multiplexing of event dispatch and tracking of overlays * to make things easier for WindowContainer. + * + * These overlays are to be used for various types of System UI and UI + * under the systems control. Provided SurfacePackages will be able + * to overlay application content, without engaging the usual cross process + * obscured touch filtering mechanisms. It's imperative that all UI provided + * be under complete control of the system. */ -class OverlayHost { +class TrustedOverlayHost { // Lazily initialized when required SurfaceControl mSurfaceControl; final ArrayList<SurfaceControlViewHost.SurfacePackage> mOverlays = new ArrayList<>(); final WindowManagerService mWmService; - OverlayHost(WindowManagerService wms) { + TrustedOverlayHost(WindowManagerService wms) { mWmService = wms; } @@ -51,6 +57,8 @@ class OverlayHost { .setName("Overlay Host Leash"); mSurfaceControl = b.build(); + SurfaceControl.Transaction t = mWmService.mTransactionFactory.get(); + t.setTrustedOverlay(mSurfaceControl, true).apply(); } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 1bd153b2a577..8a373bf5c09c 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -314,7 +314,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private final List<WindowContainerListener> mListeners = new ArrayList<>(); - protected OverlayHost mOverlayHost; + protected TrustedOverlayHost mOverlayHost; WindowContainer(WindowManagerService wms) { mWmService = wms; @@ -3600,9 +3600,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< @AnimationType int type, @Nullable AnimationAdapter snapshotAnim); } - void addOverlay(SurfaceControlViewHost.SurfacePackage overlay) { + void addTrustedOverlay(SurfaceControlViewHost.SurfacePackage overlay) { if (mOverlayHost == null) { - mOverlayHost = new OverlayHost(mWmService); + mOverlayHost = new TrustedOverlayHost(mWmService); } mOverlayHost.addOverlay(overlay, mSurfaceControl); @@ -3613,11 +3613,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< overlay.getRemoteInterface().onConfigurationChanged(getConfiguration()); } catch (Exception e) { Slog.e(TAG, "Error sending initial configuration change to WindowContainer overlay"); - removeOverlay(overlay); + removeTrustedOverlay(overlay); } } - void removeOverlay(SurfaceControlViewHost.SurfacePackage overlay) { + void removeTrustedOverlay(SurfaceControlViewHost.SurfacePackage overlay) { if (mOverlayHost != null && !mOverlayHost.removeOverlay(overlay)) { mOverlayHost.release(); mOverlayHost = null; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 4900f9292f2a..9585a4b93a97 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -827,6 +827,11 @@ public abstract class WindowManagerInternal { * Internal methods for other parts of SystemServer to manage * SurfacePackage based overlays on tasks. * + * Since these overlays will overlay application content, they exist + * in a container with setTrustedOverlay(true). This means its imperative + * that this overlay feature only be used with UI completely under the control + * of the system, without 3rd party content. + * * Callers prepare a view hierarchy with SurfaceControlViewHost * and send the package to WM here. The remote view hierarchy will receive * configuration change, lifecycle events, etc, forwarded over the @@ -837,8 +842,10 @@ public abstract class WindowManagerInternal { * The embedded hierarchy exists in a coordinate space relative to the task * bounds. */ - public abstract void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay); - public abstract void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay); + public abstract void addTrustedTaskOverlay(int taskId, + SurfaceControlViewHost.SurfacePackage overlay); + public abstract void removeTrustedTaskOverlay(int taskId, + SurfaceControlViewHost.SurfacePackage overlay); /** * Get a SurfaceControl that is the container layer that should be used to receive input to diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 22c430ff8016..c9c3f1da5b40 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.INPUT_CONSUMER; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.Manifest.permission.MANAGE_APP_TOKENS; +import static android.Manifest.permission.MODIFY_TOUCH_MODE_STATE; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; @@ -38,6 +39,7 @@ import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; +import static android.os.Process.myUid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW; @@ -706,6 +708,7 @@ public class WindowManagerService extends IWindowManager.Stub final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2; int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE; + /** Indicates that the system server is actively demanding the screen be frozen. */ boolean mClientFreezingScreen = false; int mAppsFreezingScreen = 0; @@ -1185,7 +1188,8 @@ public class WindowManagerService extends IWindowManager.Stub com.android.internal.R.bool.config_hasPermanentDpad); mInTouchMode = context.getResources().getBoolean( com.android.internal.R.bool.config_defaultInTouchMode); - inputManager.setInTouchMode(mInTouchMode); + inputManager.setInTouchMode( + mInTouchMode, myPid(), myUid(), /* hasPermission = */ true); mDrawLockTimeoutMillis = context.getResources().getInteger( com.android.internal.R.integer.config_drawLockTimeoutMillis); mAllowAnimationsInLowPowerMode = context.getResources().getBoolean( @@ -2651,7 +2655,6 @@ public class WindowManagerService extends IWindowManager.Stub } boolean checkCallingPermission(String permission, String func, boolean printLog) { - // Quick check: if the calling permission is me, it's all okay. if (Binder.getCallingPid() == myPid()) { return true; } @@ -3091,6 +3094,7 @@ public class WindowManagerService extends IWindowManager.Stub // Misc IWindowSession methods // ------------------------------------------------------------- + /** Freeze the screen during a user-switch event. Called by UserController. */ @Override public void startFreezingScreen(int exitAnim, int enterAnim) { if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN, @@ -3113,6 +3117,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * No longer actively demand that the screen remain frozen. + * Called by UserController after a user-switch. + * This doesn't necessarily immediately unlock the screen; it just allows it if we're ready. + */ @Override public void stopFreezingScreen() { if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN, @@ -3685,12 +3694,33 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override + /** + * Sets the touch mode state. + * + * To be able to change touch mode state, the caller must either own the focused window, or must + * have the MODIFY_TOUCH_MODE_STATE permission. + * + * @param mode the touch mode to set + */ + @Override // Binder call public void setInTouchMode(boolean mode) { synchronized (mGlobalLock) { - mInTouchMode = mode; + if (mInTouchMode == mode) { + return; + } + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final boolean hasPermission = checkCallingPermission(MODIFY_TOUCH_MODE_STATE, + "setInTouchMode()"); + final long token = Binder.clearCallingIdentity(); + try { + if (mInputManager.setInTouchMode(mode, pid, uid, hasPermission)) { + mInTouchMode = mode; + } + } finally { + Binder.restoreCallingIdentity(token); + } } - mInputManager.setInTouchMode(mode); } boolean getInTouchMode() { @@ -5863,6 +5893,13 @@ public class WindowManagerService extends IWindowManager.Stub return; } + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.doStartFreezingDisplay"); + doStartFreezingDisplay(exitAnim, enterAnim, displayContent, overrideOriginalRotation); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } + + private void doStartFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent, + int overrideOriginalRotation) { ProtoLog.d(WM_DEBUG_ORIENTATION, "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", exitAnim, enterAnim, Debug.getCallers(8)); @@ -5933,10 +5970,16 @@ public class WindowManagerService extends IWindowManager.Stub return; } + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.doStopFreezingDisplayLocked-" + + mLastFinishedFreezeSource); + doStopFreezingDisplayLocked(displayContent); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } + + private void doStopFreezingDisplayLocked(DisplayContent displayContent) { ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Unfreezing now"); - // We must make a local copy of the displayId as it can be potentially overwritten later on // in this method. For example, {@link startFreezingDisplayLocked} may be called as a result // of update rotation, but we reference the frozen display after that call in this method. @@ -7969,27 +8012,29 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) { return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken); - } + } @Override - public void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) { + public void addTrustedTaskOverlay(int taskId, + SurfaceControlViewHost.SurfacePackage overlay) { synchronized (mGlobalLock) { final Task task = mRoot.getRootTask(taskId); if (task == null) { throw new IllegalArgumentException("no task with taskId" + taskId); } - task.addOverlay(overlay); + task.addTrustedOverlay(overlay); } } @Override - public void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) { + public void removeTrustedTaskOverlay(int taskId, + SurfaceControlViewHost.SurfacePackage overlay) { synchronized (mGlobalLock) { final Task task = mRoot.getRootTask(taskId); if (task == null) { throw new IllegalArgumentException("no task with taskId" + taskId); } - task.removeOverlay(overlay); + task.removeTrustedOverlay(overlay); } } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 99abf440910e..f9de53ce8016 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -44,7 +44,6 @@ cc_library_static { "com_android_server_lights_LightsService.cpp", "com_android_server_location_GnssLocationProvider.cpp", "com_android_server_locksettings_SyntheticPasswordManager.cpp", - "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", "com_android_server_powerstats_PowerStatsService.cpp", "com_android_server_hint_HintManagerService.cpp", @@ -71,7 +70,6 @@ cc_library_static { "com_android_server_wm_TaskFpsCallbackController.cpp", "onload.cpp", ":lib_cachedAppOptimizer_native", - ":lib_networkStatsFactory_native", ":lib_gameManagerService_native", ], @@ -86,7 +84,6 @@ cc_library_static { header_libs: [ "bionic_libc_platform_headers", - "bpf_connectivity_headers", ], } @@ -145,9 +142,6 @@ cc_defaults { "libhidlbase", "libutils", "libhwui", - "libbpf_android", - "libnetdutils", - "libnetworkstats", "libpsi", "libdataloader", "libincfs", @@ -214,13 +208,6 @@ cc_defaults { } filegroup { - name: "lib_networkStatsFactory_native", - srcs: [ - "com_android_server_net_NetworkStatsFactory.cpp", - ], -} - -filegroup { name: "lib_cachedAppOptimizer_native", srcs: [ "com_android_server_am_CachedAppOptimizer.cpp", diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index e5529f1997a3..3c122b03d0d1 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1704,7 +1704,6 @@ static void nativePilferPointers(JNIEnv* env, jclass /* clazz */, jlong ptr, job im->pilferPointers(token); } - static void nativeSetInputFilterEnabled(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jboolean enabled) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1712,11 +1711,13 @@ static void nativeSetInputFilterEnabled(JNIEnv* /* env */, jclass /* clazz */, im->getInputManager()->getDispatcher().setInputFilterEnabled(enabled); } -static void nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */, - jlong ptr, jboolean inTouchMode) { +static jboolean nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, + jboolean inTouchMode, jint pid, jint uid, + jboolean hasPermission) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode); + return im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode, pid, uid, + hasPermission); } static void nativeSetMaximumObscuringOpacityForTouch(JNIEnv* /* env */, jclass /* clazz */, @@ -2383,7 +2384,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel}, {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers}, {"nativeSetInputFilterEnabled", "(JZ)V", (void*)nativeSetInputFilterEnabled}, - {"nativeSetInTouchMode", "(JZ)V", (void*)nativeSetInTouchMode}, + {"nativeSetInTouchMode", "(JZIIZ)Z", (void*)nativeSetInTouchMode}, {"nativeSetMaximumObscuringOpacityForTouch", "(JF)V", (void*)nativeSetMaximumObscuringOpacityForTouch}, {"nativeSetBlockUntrustedTouchesMode", "(JI)V", (void*)nativeSetBlockUntrustedTouchesMode}, diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index ba5b3f54efa1..1c6a3b5eb03f 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -51,8 +51,6 @@ int register_android_server_Watchdog(JNIEnv* env); int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); -int register_android_server_net_NetworkStatsFactory(JNIEnv* env); -int register_android_server_net_NetworkStatsService(JNIEnv* env); int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); @@ -110,8 +108,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_SyntheticPasswordManager(env); register_android_graphics_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); - register_android_server_net_NetworkStatsFactory(env); - register_android_server_net_NetworkStatsService(env); register_android_server_am_CachedAppOptimizer(env); register_android_server_am_LowMemDetector(env); register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml index c5b054949bc5..69e13b38873a 100644 --- a/services/core/lint-baseline.xml +++ b/services/core/lint-baseline.xml @@ -1,158 +1,140 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev"> +<issues format="5" by="lint 7.2.0-dev"> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" return Settings.Secure.getInt(context.getContentResolver()," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java" - line="1106" - column="20"/> + line="1122"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" return Settings.Secure.getInt(context.getContentResolver()," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java" - line="1111" - column="20"/> + line="1127"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. " - errorLine1=" return Settings.Secure.getString(mContentResolver, mKey);" - errorLine2=" ~~~~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/CertBlacklister.java" - line="73" - column="36"/> + file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java" + line="670"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" }" - errorLine2=" ^"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/clipboard/ClipboardService.java" - line="973" - column="7"/> + file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java" + line="678"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" boolean accessibilityEnabled = Settings.Secure.getInt(cr," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/DockObserver.java" - line="176" - column="60"/> + file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java" + line="679"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. " - errorLine1=" String mediaButtonReceiverInfo = Settings.Secure.getString(mContentResolver," - errorLine2=" ~~~~~~~~~"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/media/MediaSessionService.java" - line="928" - column="46"/> + file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java" + line="696"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" final boolean isSecureFrpEnabled =" - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java" - line="1959" - column="36"/> + file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java" + line="705"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" private int getUnknownSourcesSettings() {" - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java" - line="16741" - column="39"/> + file="frameworks/base/services/core/java/com/android/server/CertBlacklister.java" + line="73"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. " - errorLine1=" String inputMethodComponent = Settings.Secure.getString(mContext.getContentResolver()," - errorLine2=" ~~~~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location - file="frameworks/base/services/core/java/com/android/server/SensorPrivacyService.java" - line="489" - column="35"/> + file="frameworks/base/services/core/java/com/android/server/clipboard/ClipboardService.java" + line="1072"/> + </issue> + + <issue + id="NonUserGetterCalled" + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> + <location + file="frameworks/base/services/core/java/com/android/server/DockObserver.java" + line="260"/> + </issue> + + <issue + id="NonUserGetterCalled" + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> + <location + file="frameworks/base/services/core/java/com/android/server/media/MediaSessionService.java" + line="928"/> + </issue> + + <issue + id="NonUserGetterCalled" + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> + <location + file="frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java" + line="1902"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. " - errorLine1=" return Settings.Secure.getString(getContentResolverAsUser(userId), key);" - errorLine2=" ~~~~~~~~~"> + message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java" - line="1994" - column="12"/> + line="2069"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" return Settings.Secure.getInt(getContentResolverAsUser(userId), key, def);" - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java" - line="2001" - column="12"/> + line="2076"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" if (Settings.Secure.getInt(mContext.getContentResolver()," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java" - line="980" - column="45"/> + line="984"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" && Settings.Secure.getInt(mContext.getContentResolver()," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java" - line="1442" - column="36"/> + line="1446"/> </issue> <issue id="NonUserGetterCalled" - message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. " - errorLine1=" && Settings.Secure.getInt(mContext.getContentResolver()," - errorLine2=" ~~~~~~"> + message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "> <location file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java" - line="1444" - column="36"/> + line="1448"/> </issue> </issues> diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 762d4c1b9a78..846577034ca8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11615,6 +11615,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who); Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) + || isFinancedDeviceOwner(caller) || isProfileOwner(caller) || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller))); @@ -13990,7 +13991,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { if (isFinancedDeviceOwner(caller)) { - enforceCanSetPermissionGrantOnFinancedDevice(packageName, permission); + enforcePermissionGrantStateOnFinancedDevice(packageName, permission); } long ident = mInjector.binderClearCallingIdentity(); try { @@ -14051,14 +14052,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void enforceCanSetPermissionGrantOnFinancedDevice( + private void enforcePermissionGrantStateOnFinancedDevice( String packageName, String permission) { if (!Manifest.permission.READ_PHONE_STATE.equals(permission)) { - throw new SecurityException("Cannot grant " + permission - + " when managing a financed device"); + throw new SecurityException(permission + " cannot be used when managing a financed" + + " device for permission grant state"); } else if (!mOwners.getDeviceOwnerPackageName().equals(packageName)) { - throw new SecurityException("Cannot grant permission to a package that is not" - + " the device owner"); + throw new SecurityException("Device owner package is the only package that can be used" + + " for permission grant state when managing a financed device"); } } @@ -14067,10 +14068,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { String packageName, String permission) throws RemoteException { final CallerIdentity caller = getCallerIdentity(admin, callerPackage); Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent() - && (isProfileOwner(caller) || isDefaultDeviceOwner(caller))) + && (isProfileOwner(caller) || isDefaultDeviceOwner(caller) + || isFinancedDeviceOwner(caller))) || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT))); synchronized (getLockObject()) { + if (isFinancedDeviceOwner(caller)) { + enforcePermissionGrantStateOnFinancedDevice(packageName, permission); + } return mInjector.binderWithCleanCallingIdentity(() -> { int granted; if (getTargetSdk(caller.getPackageName(), caller.getUserId()) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c2dec067c870..7d95d1039efe 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -54,7 +54,6 @@ import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityManager; import android.net.ConnectivityModuleConnector; import android.net.NetworkStackClient; -import android.net.TrafficStats; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -143,7 +142,6 @@ import com.android.server.media.MediaRouterService; import com.android.server.media.metrics.MediaMetricsManagerService; import com.android.server.media.projection.MediaProjectionManagerService; import com.android.server.net.NetworkPolicyManagerService; -import com.android.server.net.NetworkStatsService; import com.android.server.net.watchlist.NetworkWatchlistService; import com.android.server.notification.NotificationManagerService; import com.android.server.oemlock.OemLockService; @@ -397,6 +395,8 @@ public final class SystemServer implements Dumpable { "com.android.server.media.MediaResourceMonitorService"; private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS = "com.android.server.ConnectivityServiceInitializer"; + private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS = + "com.android.server.NetworkStatsServiceInitializer"; private static final String IP_CONNECTIVITY_METRICS_CLASS = "com.android.server.connectivity.IpConnectivityMetrics"; private static final String MEDIA_COMMUNICATION_SERVICE_CLASS = @@ -1395,7 +1395,6 @@ public final class SystemServer implements Dumpable { NetworkManagementService networkManagement = null; VpnManagerService vpnManager = null; VcnManagementService vcnManagement = null; - NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; WindowManagerService wm = null; SerialService serial = null; @@ -1917,13 +1916,10 @@ public final class SystemServer implements Dumpable { t.traceEnd(); t.traceBegin("StartNetworkStatsService"); - try { - networkStats = NetworkStatsService.create(context); - ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); - TrafficStats.init(context); - } catch (Throwable e) { - reportWtf("starting NetworkStats Service", e); - } + // This has to be called before NetworkPolicyManager because NetworkPolicyManager + // needs to take NetworkStatsService to initialize. + mSystemServiceManager.startServiceFromJar(NETWORK_STATS_SERVICE_INITIALIZER_CLASS, + CONNECTIVITY_SERVICE_APEX_PATH); t.traceEnd(); t.traceBegin("StartNetworkPolicyManagerService"); @@ -2775,7 +2771,6 @@ public final class SystemServer implements Dumpable { // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; - final NetworkStatsService networkStatsF = networkStats; final NetworkPolicyManagerService networkPolicyF = networkPolicy; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; @@ -2874,15 +2869,6 @@ public final class SystemServer implements Dumpable { .networkScoreAndNetworkManagementServiceReady(); } t.traceEnd(); - t.traceBegin("MakeNetworkStatsServiceReady"); - try { - if (networkStatsF != null) { - networkStatsF.systemReady(); - } - } catch (Throwable e) { - reportWtf("making Network Stats Service ready", e); - } - t.traceEnd(); t.traceBegin("MakeConnectivityServiceReady"); try { if (connectivityF != null) { @@ -3171,11 +3157,6 @@ public final class SystemServer implements Dumpable { } private void startAmbientContextService(@NonNull TimingsTraceAndSlog t) { - if (!AmbientContextManagerService.isDetectionServiceConfigured()) { - Slog.d(TAG, "AmbientContextDetectionService is not configured on this device"); - return; - } - t.traceBegin("StartAmbientContextService"); mSystemServiceManager.startService(AmbientContextManagerService.class); t.traceEnd(); diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java index 7f571195f5f8..ed232e5458b0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java @@ -406,7 +406,7 @@ public final class GameServiceProviderInstanceImplTest { mFakeGameSessionService.removePendingFutureForTaskId(10) .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); - verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10)); + verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10)); } @Test @@ -556,8 +556,9 @@ public final class GameServiceProviderInstanceImplTest { stopTask(10); - verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10)); - verify(mMockWindowManagerInternal).removeTaskOverlay(eq(10), eq(mockSurfacePackage10)); + verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10)); + verify(mMockWindowManagerInternal).removeTrustedTaskOverlay(eq(10), + eq(mockSurfacePackage10)); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java new file mode 100644 index 000000000000..fa3e05a6b001 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java @@ -0,0 +1,248 @@ +/* + * 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.sensorprivacy; + +import static android.app.AppOpsManager.OPSTR_CAMERA; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.times; + +import android.app.AppOpsManager; +import android.content.Context; +import android.hardware.lights.Light; +import android.hardware.lights.LightsManager; +import android.hardware.lights.LightsRequest; +import android.permission.PermissionManager; +import android.util.ArraySet; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +public class CameraPrivacyLightControllerTest { + + private MockitoSession mMockitoSession; + + @Mock + private Context mContext; + + @Mock + private LightsManager mLightsManager; + + @Mock + private AppOpsManager mAppOpsManager; + + @Mock + private LightsManager.LightsSession mLightsSession; + + private ArgumentCaptor<AppOpsManager.OnOpActiveChangedListener> mAppOpsListenerCaptor = + ArgumentCaptor.forClass(AppOpsManager.OnOpActiveChangedListener.class); + + private ArgumentCaptor<LightsRequest> mLightsRequestCaptor = + ArgumentCaptor.forClass(LightsRequest.class); + + private Set<String> mExemptedPackages = new ArraySet<>(); + private List<Light> mLights = new ArrayList<>(); + + private int mNextLightId = 1; + + @Before + public void setUp() { + mMockitoSession = ExtendedMockito.mockitoSession() + .initMocks(this) + .strictness(Strictness.WARN) + .spyStatic(PermissionManager.class) + .startMocking(); + + doReturn(mLightsManager).when(mContext).getSystemService(LightsManager.class); + doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); + + doReturn(mLights).when(mLightsManager).getLights(); + doReturn(mLightsSession).when(mLightsManager).openSession(anyInt()); + + doReturn(mExemptedPackages) + .when(() -> PermissionManager.getIndicatorExemptedPackages(any())); + } + + @After + public void tearDown() { + mExemptedPackages.clear(); + mLights.clear(); + + mMockitoSession.finishMocking(); + } + + @Test + public void testAppsOpsListenerNotRegisteredWithoutCameraLights() { + mLights.add(getNextLight(false)); + new CameraPrivacyLightController(mContext); + + verify(mAppOpsManager, times(0)).startWatchingActive(any(), any(), any()); + } + + @Test + public void testAppsOpsListenerRegisteredWithCameraLight() { + mLights.add(getNextLight(true)); + + new CameraPrivacyLightController(mContext); + + verify(mAppOpsManager, times(1)).startWatchingActive(any(), any(), any()); + } + + @Test + public void testAllCameraLightsAreRequestedOnOpActive() { + Random r = new Random(0); + for (int i = 0; i < 30; i++) { + mLights.add(getNextLight(r.nextBoolean())); + } + + new CameraPrivacyLightController(mContext); + + // Verify no session has been opened at this point. + verify(mLightsManager, times(0)).openSession(anyInt()); + + // Set camera op as active. + verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture()); + mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true); + + // Verify session has been opened exactly once + verify(mLightsManager, times(1)).openSession(anyInt()); + + verify(mLightsSession).requestLights(mLightsRequestCaptor.capture()); + assertEquals("requestLights() not invoked exactly once", + 1, mLightsRequestCaptor.getAllValues().size()); + + List<Integer> expectedCameraLightIds = mLights.stream() + .filter(l -> l.getType() == Light.LIGHT_TYPE_CAMERA) + .map(l -> l.getId()) + .collect(Collectors.toList()); + List<Integer> lightsRequestLightIds = mLightsRequestCaptor.getValue().getLights(); + + // We don't own lights framework, don't assume it will retain order + lightsRequestLightIds.sort(Integer::compare); + expectedCameraLightIds.sort(Integer::compare); + + assertEquals(expectedCameraLightIds, lightsRequestLightIds); + } + + @Test + public void testWillOnlyOpenOnceWhenTwoPackagesStartOp() { + mLights.add(getNextLight(true)); + + new CameraPrivacyLightController(mContext); + + verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture()); + + AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue(); + listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true); + verify(mLightsManager, times(1)).openSession(anyInt()); + listener.onOpActiveChanged(OPSTR_CAMERA, 10102, "pkg2", true); + verify(mLightsManager, times(1)).openSession(anyInt()); + } + + @Test + public void testWillCloseOnFinishOp() { + mLights.add(getNextLight(true)); + + new CameraPrivacyLightController(mContext); + + verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture()); + + AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue(); + listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true); + + verify(mLightsSession, times(0)).close(); + listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", false); + verify(mLightsSession, times(1)).close(); + } + + @Test + public void testWillCloseOnFinishOpForAllPackages() { + mLights.add(getNextLight(true)); + + new CameraPrivacyLightController(mContext); + + int numUids = 100; + List<Integer> uids = new ArrayList<>(numUids); + for (int i = 0; i < numUids; i++) { + uids.add(10001 + i); + } + + verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture()); + + AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue(); + + for (int i = 0; i < numUids; i++) { + listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), true); + } + + // Change the order which their ops are finished + Collections.shuffle(uids, new Random(0)); + + for (int i = 0; i < numUids - 1; i++) { + listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), false); + } + + verify(mLightsSession, times(0)).close(); + int lastUid = uids.get(numUids - 1); + listener.onOpActiveChanged(OPSTR_CAMERA, lastUid, "pkg" + lastUid, false); + verify(mLightsSession, times(1)).close(); + } + + @Test + public void testWontOpenForExemptedPackage() { + mLights.add(getNextLight(true)); + mExemptedPackages.add("pkg1"); + + new CameraPrivacyLightController(mContext); + + verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture()); + + AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue(); + listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true); + verify(mLightsManager, times(0)).openSession(anyInt()); + } + + private Light getNextLight(boolean cameraType) { + Light light = ExtendedMockito.mock(Light.class); + if (cameraType) { + doReturn(Light.LIGHT_TYPE_CAMERA).when(light).getType(); + } else { + doReturn(Light.LIGHT_TYPE_MICROPHONE).when(light).getType(); + } + doReturn(mNextLightId++).when(light).getId(); + return light; + } +} diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java index e1aa08d9176a..51607e528216 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -29,6 +29,8 @@ import static org.mockito.AdditionalAnswers.returnsArgAt; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.longThat; import static org.mockito.Mockito.doAnswer; @@ -38,6 +40,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.IActivityManager; +import android.app.usage.StorageStats; +import android.app.usage.StorageStatsManager; import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.UsageEventListener; @@ -48,6 +52,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; @@ -68,10 +73,12 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.Executor; /** @@ -104,6 +111,8 @@ public final class AppHibernationServiceTest { @Mock private UserManager mUserManager; @Mock + private StorageStatsManager mStorageStatsManager; + @Mock private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore; @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal; @@ -115,7 +124,7 @@ public final class AppHibernationServiceTest { private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor; @Before - public void setUp() throws RemoteException { + public void setUp() throws RemoteException, PackageManager.NameNotFoundException, IOException { // Share class loader to allow access to package-private classes System.setProperty("dexmaker.share_classloader", "true"); MockitoAnnotations.initMocks(this); @@ -140,6 +149,11 @@ public final class AppHibernationServiceTest { packages.add(makePackageInfo(PACKAGE_NAME_3)); doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages( longThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt()); + doReturn(mock(ApplicationInfo.class)).when(mIPackageManager).getApplicationInfo( + any(), anyLong(), anyInt()); + StorageStats storageStats = new StorageStats(); + doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage( + (UUID) any(), anyString(), any()); mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); UserInfo userInfo = addUser(USER_ID_1); @@ -381,18 +395,31 @@ public final class AppHibernationServiceTest { } @Test - public void testGetHibernationStatsForUser_getsStatsForPackage() { - // GIVEN a package is hibernating globally and for a user + public void testGetHibernationStatsForUser_getsStatsForPackage() + throws PackageManager.NameNotFoundException, IOException, RemoteException { + // GIVEN a package is hibernating globally and for a user with some storage saved + final long cacheSavings = 1000; + StorageStats storageStats = new StorageStats(); + storageStats.cacheBytes = cacheSavings; + doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage( + (UUID) any(), eq(PACKAGE_NAME_1), any()); + final long oatDeletionSavings = 2000; + doReturn(oatDeletionSavings).when(mPackageManagerInternal).deleteOatArtifactsOfPackage( + PACKAGE_NAME_1); + mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true); mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); // WHEN we ask for the hibernation stats for the package - Map<String, HibernationStats> stats = + Map<String, HibernationStats> statsMap = mAppHibernationService.getHibernationStatsForUser( Set.of(PACKAGE_NAME_1), USER_ID_1); - // THEN the stats exist for the package - assertTrue(stats.containsKey(PACKAGE_NAME_1)); + // THEN the stats exist for the package and add up to the OAT deletion and cache deletion + // savings + HibernationStats stats = statsMap.get(PACKAGE_NAME_1); + assertNotNull(stats); + assertEquals(cacheSavings + oatDeletionSavings, stats.getDiskBytesSaved()); } @Test @@ -519,6 +546,11 @@ public final class AppHibernationServiceTest { } @Override + public StorageStatsManager getStorageStatsManager() { + return mStorageStatsManager; + } + + @Override public UsageStatsManagerInternal getUsageStatsManagerInternal() { return mUsageStatsManagerInternal; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index b96bb23f8951..48e21225f6d6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -7781,6 +7781,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal, never()) .setDevicePolicyUserRestrictions(anyInt(), any(), any(), anyBoolean()); + DpmTestUtils.assertRestrictions(new Bundle(), dpm.getUserRestrictions(admin1)); } } } @@ -7812,6 +7813,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(true)); reset(getServices().userManagerInternal); + DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(restriction), + dpm.getUserRestrictions(admin1)); + dpm.clearUserRestriction(admin1, restriction); reset(getServices().userManagerInternal); } @@ -8058,6 +8062,28 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + public void testGetPermissionGrantState_financeDo_notReadPhoneStatePermission_throwsException() + throws Exception { + setDeviceOwner(); + dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED); + + assertExpectException(SecurityException.class, /* messageRegex= */ null, + () -> dpm.getPermissionGrantState(admin1, admin1.getPackageName(), + permission.READ_CALENDAR)); + } + + @Test + public void testGetPermissionGrantState_financeDo_notDeviceOwnerPackage_throwsException() + throws Exception { + setDeviceOwner(); + dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED); + + assertExpectException(SecurityException.class, /* messageRegex= */ null, + () -> dpm.getPermissionGrantState(admin1, "com.android.foo.package", + permission.READ_PHONE_STATE)); + } + + @Test public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() { assertThrows(SecurityException.class, () -> dpm.setUsbDataSignalingEnabled(true)); @@ -8338,7 +8364,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testSetSsidAllowlist_noDeviceOwnerOrPoOfOrgOwnedDevice() { final Set<WifiSsid> ssids = new ArraySet<>( Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids); assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy)); } @@ -8348,7 +8375,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { final Set<WifiSsid> ssids = new ArraySet<>( Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids); dpm.setWifiSsidPolicy(policy); assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids); assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo( @@ -8367,7 +8395,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)), WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)), WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids); dpm.setWifiSsidPolicy(policy); assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids); assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo( @@ -8380,14 +8409,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { final Set<WifiSsid> ssids = new ArraySet<>(); assertThrows(IllegalArgumentException.class, - () -> WifiSsidPolicy.createAllowlistPolicy(ssids)); + () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids)); } @Test public void testSetSsidDenylist_noDeviceOwnerOrPoOfOrgOwnedDevice() { final Set<WifiSsid> ssids = new ArraySet<>( Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids); assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy)); } @@ -8397,7 +8427,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { final Set<WifiSsid> ssids = new ArraySet<>( Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids); dpm.setWifiSsidPolicy(policy); assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids); assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo( @@ -8416,7 +8447,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)), WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)), WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8)))); - WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids); + WifiSsidPolicy policy = new WifiSsidPolicy( + WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids); dpm.setWifiSsidPolicy(policy); assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids); assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo( @@ -8429,7 +8461,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final Set<WifiSsid> ssids = new ArraySet<>(); assertThrows(IllegalArgumentException.class, - () -> WifiSsidPolicy.createDenylistPolicy(ssids)); + () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 94cf20f9c15b..a7b045f10f2c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -2237,7 +2237,7 @@ public class NetworkPolicyManagerServiceTest { private void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) throws InterruptedException { - mService.setSubscriptionPlans(subId, plans, callingPackage); + mService.setSubscriptionPlans(subId, plans, 0, callingPackage); // setSubscriptionPlans() triggers async events, wait for those to be completed before // moving forward as they could interfere with the tests later. postMsgAndWaitForCompletion(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index fd523f0585c7..ba414075e4f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -739,6 +739,9 @@ public class TransitionTests extends WindowTestsBase { } from = from.getParent(); } + if (end.asDisplayArea() != null) { + end.asDisplayArea().mOrganizer = organizer; + } } /** Fill the change map with all the parents of top. Change maps are usually fully populated */ diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index d7cdb507362a..2141c794d743 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1493,9 +1493,14 @@ public class TelecomManager { * when placing calls. The user may still need to enable the {@link PhoneAccount} within * the phone app settings before the account is usable. * <p> + * Note: Each package is limited to 10 {@link PhoneAccount} registrations. + * <p> * A {@link SecurityException} will be thrown if an app tries to register a * {@link PhoneAccountHandle} where the package name specified within * {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app. + * <p> + * A {@link IllegalArgumentException} will be thrown if an app tries to register a + * {@link PhoneAccount} when the upper bound limit, 10, has already been reached. * * @param account The complete {@link PhoneAccount}. */ diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java index 184e1541f1b0..30ed7c287421 100644 --- a/telephony/java/android/service/euicc/EuiccService.java +++ b/telephony/java/android/service/euicc/EuiccService.java @@ -257,6 +257,13 @@ public abstract class EuiccService extends Service { "android.service.euicc.extra.RESOLUTION_CARD_ID"; /** + * Intent extra set for resolution requests containing an int indicating the subscription id + * to be enabled. + */ + public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = + "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID"; + + /** * Intent extra set for resolution requests containing an int indicating the current port index. */ public static final String EXTRA_RESOLUTION_PORT_INDEX = diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java index 4978692d3964..82333a46914b 100644 --- a/telephony/java/android/telephony/ImsiEncryptionInfo.java +++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java @@ -46,16 +46,17 @@ public final class ImsiEncryptionInfo implements Parcelable { private final int keyType; //Date-Time in UTC when the key will expire. private final Date expirationTime; + private final int carrierId; /** @hide */ public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier, - byte[] key, Date expirationTime) { - this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime); + byte[] key, Date expirationTime, int carrierId) { + this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime, carrierId); } /** @hide */ public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier, - PublicKey publicKey, Date expirationTime) { + PublicKey publicKey, Date expirationTime, int carrierId) { // todo need to validate that ImsiEncryptionInfo is being created with the correct params. // Including validating that the public key is in "X.509" format. This will be done in // a subsequent CL. @@ -65,6 +66,7 @@ public final class ImsiEncryptionInfo implements Parcelable { this.publicKey = publicKey; this.keyIdentifier = keyIdentifier; this.expirationTime = expirationTime; + this.carrierId = carrierId; } /** @hide */ @@ -78,6 +80,7 @@ public final class ImsiEncryptionInfo implements Parcelable { keyIdentifier = in.readString(); keyType = in.readInt(); expirationTime = new Date(in.readLong()); + carrierId = in.readInt(); } /** @hide */ @@ -90,6 +93,11 @@ public final class ImsiEncryptionInfo implements Parcelable { return this.mcc; } + /** @hide */ + public int getCarrierId() { + return carrierId; + } + /** * Returns key identifier, a string that helps the authentication server to locate the * private key to decrypt the permanent identity, or {@code null} when uavailable. @@ -157,6 +165,7 @@ public final class ImsiEncryptionInfo implements Parcelable { dest.writeString(keyIdentifier); dest.writeInt(keyType); dest.writeLong(expirationTime.getTime()); + dest.writeInt(carrierId); } @Override @@ -164,10 +173,11 @@ public final class ImsiEncryptionInfo implements Parcelable { return "[ImsiEncryptionInfo " + "mcc=" + mcc + " mnc=" + mnc - + " publicKey=" + publicKey + + ", publicKey=" + publicKey + ", keyIdentifier=" + keyIdentifier + ", keyType=" + keyType + ", expirationTime=" + expirationTime + + ", carrier_id=" + carrierId + "]"; } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 250e55cf5014..0aaafef492bf 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2863,10 +2863,43 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if plans don't meet the requirements * defined in {@link SubscriptionPlan}. + * @deprecated use {@link #setSubscriptionPlans(int, List, long)} instead. */ + @Deprecated public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { + setSubscriptionPlans(subId, plans, 0); + } + + /** + * Set the description of the billing relationship plan between a carrier + * and a specific subscriber. + * <p> + * This method is only accessible to the following narrow set of apps: + * <ul> + * <li>The carrier app for this subscriberId, as determined by + * {@link TelephonyManager#hasCarrierPrivileges()}. + * <li>The carrier app explicitly delegated access through + * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}. + * </ul> + * + * @param subId the subscriber this relationship applies to. An empty list + * may be sent to clear any existing plans. + * @param plans the list of plans. The first plan is always the primary and + * most important plan. Any additional plans are secondary and + * may not be displayed or used by decision making logic. + * @param expirationDurationMillis the duration after which the subscription plans + * will be automatically cleared, or {@code 0} to leave the plans until + * explicitly cleared, or the next reboot, whichever happens first. + * @throws SecurityException if the caller doesn't meet the requirements + * outlined above. + * @throws IllegalArgumentException if plans don't meet the requirements + * defined in {@link SubscriptionPlan}. + */ + public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans, + @DurationMillisLong long expirationDurationMillis) { getNetworkPolicyManager().setSubscriptionPlans(subId, - plans.toArray(new SubscriptionPlan[plans.size()]), mContext.getOpPackageName()); + plans.toArray(new SubscriptionPlan[0]), expirationDurationMillis, + mContext.getOpPackageName()); } /** @@ -2885,17 +2918,17 @@ public class SubscriptionManager { * @param subId the subscriber this override applies to. * @param overrideUnmetered set if the billing relationship should be * considered unmetered. - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the + * @param expirationDurationMillis the duration after which the requested override + * will be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, - @DurationMillisLong long timeoutMillis) { + @DurationMillisLong long expirationDurationMillis) { setSubscriptionOverrideUnmetered(subId, overrideUnmetered, - TelephonyManager.getAllNetworkTypes(), timeoutMillis); + TelephonyManager.getAllNetworkTypes(), expirationDurationMillis); } /** @@ -2917,8 +2950,8 @@ public class SubscriptionManager { * @param networkTypes the network types this override applies to. If no * network types are specified, override values will be ignored. * {@see TelephonyManager#getAllNetworkTypes()} - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the + * @param expirationDurationMillis the duration after which the requested override + * will be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. * @throws SecurityException if the caller doesn't meet the requirements @@ -2926,10 +2959,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @NonNull @Annotation.NetworkType int[] networkTypes, - @DurationMillisLong long timeoutMillis) { + @DurationMillisLong long expirationDurationMillis) { final int overrideValue = overrideUnmetered ? SUBSCRIPTION_OVERRIDE_UNMETERED : 0; getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_UNMETERED, - overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName()); + overrideValue, networkTypes, expirationDurationMillis, mContext.getOpPackageName()); } /** @@ -2949,17 +2982,17 @@ public class SubscriptionManager { * @param subId the subscriber this override applies to. * @param overrideCongested set if the subscription should be considered * congested. - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the + * @param expirationDurationMillis the duration after which the requested override + * will be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, - @DurationMillisLong long timeoutMillis) { + @DurationMillisLong long expirationDurationMillis) { setSubscriptionOverrideCongested(subId, overrideCongested, - TelephonyManager.getAllNetworkTypes(), timeoutMillis); + TelephonyManager.getAllNetworkTypes(), expirationDurationMillis); } /** @@ -2982,8 +3015,8 @@ public class SubscriptionManager { * @param networkTypes the network types this override applies to. If no * network types are specified, override values will be ignored. * {@see TelephonyManager#getAllNetworkTypes()} - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the + * @param expirationDurationMillis the duration after which the requested override + * will be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. * @throws SecurityException if the caller doesn't meet the requirements @@ -2991,10 +3024,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, @NonNull @Annotation.NetworkType int[] networkTypes, - @DurationMillisLong long timeoutMillis) { + @DurationMillisLong long expirationDurationMillis) { final int overrideValue = overrideCongested ? SUBSCRIPTION_OVERRIDE_CONGESTED : 0; getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_CONGESTED, - overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName()); + overrideValue, networkTypes, expirationDurationMillis, mContext.getOpPackageName()); } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index baccb2646516..ba1a6edd74ad 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -9199,7 +9199,8 @@ public class TelephonyManager { * @param allowedNetworkTypes The bitmask of allowed network types. * @return true on success; false on any failure. * @hide - * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead. + * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead with reason + * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}. */ @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -9233,10 +9234,7 @@ public class TelephonyManager { /** * To indicate allowed network type change is requested by user. - * - * @hide */ - @SystemApi public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; /** @@ -9255,10 +9253,7 @@ public class TelephonyManager { * Carrier configuration won't affect the settings configured through * other reasons and will result in allowing network types that are in both * configurations (i.e intersection of both sets). - * - * @hide */ - @SystemApi public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; /** @@ -9272,35 +9267,23 @@ public class TelephonyManager { /** * Set the allowed network types of the device and provide the reason triggering the allowed * network change. + * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or + * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * This can be called for following reasons * <ol> * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER} - * <li>Allowed network types control by power manager - * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER} * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} - * <li>Allowed network types control by the user-controlled "Allow 2G" toggle - * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G} * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. * - * The functionality of this API with the parameter - * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API - * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of - * {@link TelephonyManager#setAllowedNetworkTypes}. - * <p> - * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} - * ({@link TelephonyManager#CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK}) returns true, then - * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, - * setPreferredNetworkTypesBitmap is used instead. - * * @param reason the reason the allowed network type change is taking place - * @param allowedNetworkTypes The bitmask of allowed network types. + * @param allowedNetworkTypes The bitmask of allowed network type * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. - * @hide + * @throws SecurityException if the caller does not have the required privileges */ - @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", @@ -9330,18 +9313,19 @@ public class TelephonyManager { * * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a * specific reason. + * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or + * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param reason the reason the allowed network type change is taking place * @return the allowed network type bitmask * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. - * @hide + * @throws SecurityException if the caller does not have the required permission/privileges */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", value = TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK) - @SystemApi public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { if (!isValidAllowedNetworkTypesReason(reason)) { @@ -13560,127 +13544,88 @@ public class TelephonyManager { // 2G /** * network type bitmask unknown. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; /** * network type bitmask indicating the support of radio tech GSM. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_GSM = (1 << (NETWORK_TYPE_GSM -1)); /** * network type bitmask indicating the support of radio tech GPRS. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_GPRS = (1 << (NETWORK_TYPE_GPRS -1)); /** * network type bitmask indicating the support of radio tech EDGE. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EDGE = (1 << (NETWORK_TYPE_EDGE -1)); /** * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B). - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_CDMA = (1 << (NETWORK_TYPE_CDMA -1)); /** * network type bitmask indicating the support of radio tech 1xRTT. - * @hide */ - @SystemApi + @SuppressLint("AllUpper") public static final long NETWORK_TYPE_BITMASK_1xRTT = (1 << (NETWORK_TYPE_1xRTT - 1)); // 3G /** * network type bitmask indicating the support of radio tech EVDO 0. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_0 = (1 << (NETWORK_TYPE_EVDO_0 -1)); /** * network type bitmask indicating the support of radio tech EVDO A. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_A = (1 << (NETWORK_TYPE_EVDO_A - 1)); /** * network type bitmask indicating the support of radio tech EVDO B. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_B = (1 << (NETWORK_TYPE_EVDO_B -1)); /** * network type bitmask indicating the support of radio tech EHRPD. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EHRPD = (1 << (NETWORK_TYPE_EHRPD -1)); /** * network type bitmask indicating the support of radio tech HSUPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSUPA = (1 << (NETWORK_TYPE_HSUPA -1)); /** * network type bitmask indicating the support of radio tech HSDPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSDPA = (1 << (NETWORK_TYPE_HSDPA -1)); /** * network type bitmask indicating the support of radio tech HSPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1)); /** * network type bitmask indicating the support of radio tech HSPAP. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1)); /** * network type bitmask indicating the support of radio tech UMTS. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_UMTS = (1 << (NETWORK_TYPE_UMTS -1)); /** * network type bitmask indicating the support of radio tech TD_SCDMA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = (1 << (NETWORK_TYPE_TD_SCDMA -1)); // 4G /** * network type bitmask indicating the support of radio tech LTE. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1)); /** * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation). - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1)); /** * network type bitmask indicating the support of radio tech NR(New Radio) 5G. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_NR = (1 << (NETWORK_TYPE_NR -1)); /** * network type bitmask indicating the support of radio tech IWLAN. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1)); /** @hide */ @@ -13735,12 +13680,11 @@ public class TelephonyManager { /** * @return Modem supported radio access family bitmask * - * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). - * @hide + * + * @throws SecurityException if the caller does not have the required permission */ - @SystemApi - @TestApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NetworkTypeBitMask long getSupportedRadioAccessFamily() { diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml index c30d76137f76..21256d8c9d0b 100644 --- a/tests/SilkFX/AndroidManifest.xml +++ b/tests/SilkFX/AndroidManifest.xml @@ -20,17 +20,20 @@ <uses-sdk android:minSdkVersion="30"/> <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:label="SilkFX" android:theme="@android:style/Theme.Material"> <activity android:name=".Main" android:label="SilkFX Demos" + android:banner="@drawable/background1" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> </intent-filter> </activity> @@ -41,13 +44,16 @@ <activity android:name=".materials.GlassActivity" android:label="Glass Examples" - android:banner="@drawable/background1" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> </intent-filter> </activity> + <activity android:name=".materials.BackgroundBlurActivity" + android:theme="@style/Theme.BackgroundBlurTheme" + android:exported="true"> + </activity> + </application> </manifest> diff --git a/tests/SilkFX/res/drawable/background_blur_drawable.xml b/tests/SilkFX/res/drawable/background_blur_drawable.xml new file mode 100644 index 000000000000..173ca99bdfdf --- /dev/null +++ b/tests/SilkFX/res/drawable/background_blur_drawable.xml @@ -0,0 +1,20 @@ +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#20FFFFFF"/> + <corners android:radius="10dp"/> +</shape> diff --git a/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml new file mode 100644 index 000000000000..bd8942d46383 --- /dev/null +++ b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="10dp"/> +</shape> diff --git a/tests/SilkFX/res/layout/activity_background_blur.xml b/tests/SilkFX/res/layout/activity_background_blur.xml new file mode 100644 index 000000000000..f13c0883cb01 --- /dev/null +++ b/tests/SilkFX/res/layout/activity_background_blur.xml @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/background" + android:layout_width="390dp" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:padding="15dp" + android:orientation="vertical" + tools:context=".materials.BackgroundBlurActivity"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:padding="10dp" + android:textColor="#ffffffff" + android:text="Hello blurry world!"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Background blur"/> + + <SeekBar + android:id="@+id/set_background_blur" + android:min="0" + android:max="300" + android:layout_width="160dp" + android:layout_height="wrap_content"/> + <TextView + android:id="@+id/background_blur_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="#ffffffff" + android:ems="3" + android:gravity="center" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Background alpha"/> + + <SeekBar + android:id="@+id/set_background_alpha" + android:min="0" + android:max="100" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/background_alpha" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="#ffffffff" + android:ems="3" + android:gravity="center" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Blur behind"/> + + <SeekBar + android:id="@+id/set_blur_behind" + android:min="0" + android:max="300" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/blur_behind_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="#ffffffff" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:ems="3" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Dim amount"/> + + <SeekBar + android:id="@+id/set_dim_amount" + android:min="0" + android:max="100" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/dim_amount" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="#ffffffff" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:ems="3" + android:text="TODO"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="5dp" + android:orientation="vertical" + android:gravity="center"> + + <Button + android:id="@+id/toggle_blur_enabled" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Disable blur" + android:onClick="toggleForceBlurDisabled"/> + + <Button + android:id="@+id/toggle_battery_saving_mode" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="TODO" + android:onClick="toggleBatterySavingMode"/> + </LinearLayout> + <requestFocus/> + +</LinearLayout> diff --git a/tests/SilkFX/res/values/style.xml b/tests/SilkFX/res/values/style.xml new file mode 100644 index 000000000000..66edbb5c9382 --- /dev/null +++ b/tests/SilkFX/res/values/style.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<!-- Styles for immersive actions UI. --> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="Theme.BackgroundBlurTheme" parent= "Theme.AppCompat.Dialog"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBlurBehindEnabled">true</item> + <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowElevation">0dp</item> + <item name="buttonStyle">@style/AppTheme.Button</item> + <item name="colorAccent">#bbffffff</item> + </style> + <style name="AppTheme.Button" parent="Widget.AppCompat.Button"> + <item name="android:textColor">#ffffffff</item> + </style> + +</resources> diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt index 9ed8d2f5edf7..7132ae8772ea 100644 --- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt +++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * 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. @@ -30,6 +30,7 @@ import com.android.test.silkfx.app.EXTRA_LAYOUT import com.android.test.silkfx.app.EXTRA_TITLE import com.android.test.silkfx.hdr.GlowActivity import com.android.test.silkfx.materials.GlassActivity +import com.android.test.silkfx.materials.BackgroundBlurActivity import kotlin.reflect.KClass class Demo(val name: String, val makeIntent: (Context) -> Intent) { @@ -51,7 +52,8 @@ private val AllDemos = listOf( Demo("Blingy Notifications", R.layout.bling_notifications) )), DemoGroup("Materials", listOf( - Demo("Glass", GlassActivity::class) + Demo("Glass", GlassActivity::class), + Demo("Background Blur", BackgroundBlurActivity::class) )) ) @@ -126,4 +128,4 @@ class Main : Activity() { AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) } } -}
\ No newline at end of file +} diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt new file mode 100644 index 000000000000..9d17d38d4298 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt @@ -0,0 +1,189 @@ +/* + * 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.test.silkfx.materials + +import android.app.Activity +import android.content.Intent +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.PaintDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.provider.Settings +import android.util.TypedValue +import android.view.View +import android.view.WindowManager +import android.widget.ImageView +import android.widget.SeekBar +import android.widget.Switch +import android.widget.TextView +import com.android.test.silkfx.R +import com.android.internal.graphics.drawable.BackgroundBlurDrawable +import android.widget.LinearLayout +import android.widget.Button + +import android.view.ViewRootImpl + +class BackgroundBlurActivity : Activity(), SeekBar.OnSeekBarChangeListener { + var mBackgroundDrawable = PaintDrawable(Color.WHITE) + var mBackgroundBlurRadius = 50 + var mAlphaWithBlur = 0.2f + var mAlphaNoBlur = 0.5f + + var mBlurBehindRadius = 10 + var mDimAmountWithBlur = 0.2f + var mDimAmountNoBlur = 0.2f + + var mBlurForceDisabled = false + var mBatterySavingModeOn = false + + lateinit var blurBackgroundSeekBar: SeekBar + lateinit var backgroundAlphaSeekBar : SeekBar + lateinit var blurBehindSeekBar : SeekBar + lateinit var dimAmountSeekBar : SeekBar + + val blurEnabledListener = { enabled : Boolean -> + blurBackgroundSeekBar.setProgress(mBackgroundBlurRadius) + blurBehindSeekBar.setProgress(mBlurBehindRadius) + + if (enabled) { + setBackgroundBlur(mBackgroundBlurRadius) + setBackgroundColorAlpha(mAlphaWithBlur) + + setBlurBehind(mBlurBehindRadius) + setDimAmount(mDimAmountWithBlur) + + backgroundAlphaSeekBar.setProgress((mAlphaWithBlur * 100).toInt()) + dimAmountSeekBar.setProgress((mDimAmountWithBlur * 100).toInt()) + } else { + setBackgroundColorAlpha(mAlphaNoBlur) + setDimAmount(mDimAmountNoBlur) + + backgroundAlphaSeekBar.setProgress((mAlphaNoBlur * 100).toInt()) + dimAmountSeekBar.setProgress((mDimAmountNoBlur * 100).toInt()) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_background_blur) + + window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) + window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + + mBackgroundDrawable.setCornerRadius(30f) + window.setBackgroundDrawable(mBackgroundDrawable) + + mBatterySavingModeOn = + Settings.Global.getInt(getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) == 1 + setBatterySavingModeOn(mBatterySavingModeOn) + + blurBackgroundSeekBar = requireViewById(R.id.set_background_blur) + backgroundAlphaSeekBar = requireViewById(R.id.set_background_alpha) + blurBehindSeekBar = requireViewById(R.id.set_blur_behind) + dimAmountSeekBar = requireViewById(R.id.set_dim_amount) + + arrayOf(blurBackgroundSeekBar, backgroundAlphaSeekBar, blurBehindSeekBar, dimAmountSeekBar) + .forEach { + it.setOnSeekBarChangeListener(this) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + getWindowManager().addCrossWindowBlurEnabledListener(blurEnabledListener) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + getWindowManager().removeCrossWindowBlurEnabledListener(blurEnabledListener) + } + + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + when (seekBar) { + blurBackgroundSeekBar -> setBackgroundBlur(progress) + backgroundAlphaSeekBar -> setBackgroundColorAlpha(progress / 100.0f) + blurBehindSeekBar -> setBlurBehind(progress) + dimAmountSeekBar -> setDimAmount(progress / 100.0f) + else -> throw IllegalArgumentException("Unknown seek bar") + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + + fun setBlurDisabled(disabled: Boolean) { + mBlurForceDisabled = disabled + Settings.Global.putInt(getContentResolver(), Settings.Global.DISABLE_WINDOW_BLURS, + if (mBlurForceDisabled) 1 else 0) + (findViewById(R.id.toggle_blur_enabled) as Button) + .setText(if (mBlurForceDisabled) "Enable blurs" else "Disable blurs") + } + + fun toggleForceBlurDisabled(v: View) { + setBlurDisabled(!mBlurForceDisabled) + } + + fun setBackgroundBlur(radius: Int) { + mBackgroundBlurRadius = radius + (findViewById(R.id.background_blur_radius) as TextView).setText(radius.toString()) + window.setBackgroundBlurRadius(mBackgroundBlurRadius) + } + + fun setBlurBehind(radius: Int) { + mBlurBehindRadius = radius + (findViewById(R.id.blur_behind_radius) as TextView).setText(radius.toString()) + window.getAttributes().setBlurBehindRadius(mBlurBehindRadius) + window.setAttributes(window.getAttributes()) + } + + fun setDimAmount(amount: Float) { + if (getWindowManager().isCrossWindowBlurEnabled()) { + mDimAmountWithBlur = amount + } else { + mDimAmountNoBlur = amount + } + (findViewById(R.id.dim_amount) as TextView).setText("%.2f".format(amount)) + window.getAttributes().dimAmount = amount + window.setAttributes(window.getAttributes()) + } + + fun setBatterySavingModeOn(on: Boolean) { + mBatterySavingModeOn = on + Settings.Global.putInt(getContentResolver(), + Settings.Global.LOW_POWER_MODE, if (on) 1 else 0) + (findViewById(R.id.toggle_battery_saving_mode) as Button).setText( + if (on) "Exit low power mode" else "Enter low power mode") + } + + fun toggleBatterySavingMode(v: View) { + setBatterySavingModeOn(!mBatterySavingModeOn) + } + + fun setBackgroundColorAlpha(alpha: Float) { + if (getWindowManager().isCrossWindowBlurEnabled()) { + mAlphaWithBlur = alpha + } else { + mAlphaNoBlur = alpha + } + (findViewById(R.id.background_alpha) as TextView).setText("%.2f".format(alpha)) + mBackgroundDrawable.setAlpha((alpha * 255f).toInt()) + getWindowManager().updateViewLayout(window.getDecorView(), window.getAttributes()) + } +} diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp deleted file mode 100644 index f87ca2ef928b..000000000000 --- a/tests/benchmarks/Android.bp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2015 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. - -// build framework base core benchmarks -// ============================================================ - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -java_library { - name: "networkStatsFactory-benchmarks", - installable: true, - - srcs: ["src/**/*.java"], - - libs: [ - "caliper-api-target", - "services.core", - ], - -} diff --git a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java deleted file mode 100644 index ef014f0d4e53..000000000000 --- a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import android.net.NetworkStats; -import android.os.SystemClock; -import com.android.server.net.NetworkStatsFactory; -import com.google.caliper.AfterExperiment; -import com.google.caliper.BeforeExperiment; -import java.io.File; - -public class NetworkStatsFactoryBenchmark { - private File mStats; - - // TODO: consider staging stats file with different number of rows - - @BeforeExperiment - protected void setUp() { - mStats = new File("/proc/net/xt_qtaguid/stats"); - } - - @AfterExperiment - protected void tearDown() { - mStats = null; - } - - public void timeReadNetworkStatsDetailJava(int reps) throws Exception { - for (int i = 0; i < reps; i++) { - NetworkStatsFactory.javaReadNetworkStatsDetail(mStats, NetworkStats.UID_ALL, - // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70 - // Fixed compilation problem but needs addressing properly. - new String[0], 999); - } - } - - public void timeReadNetworkStatsDetailNative(int reps) { - for (int i = 0; i < reps; i++) { - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - NetworkStatsFactory.nativeReadNetworkStatsDetail( - stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL, - // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70 - // Fixed compilation problem but needs addressing properly. - new String[0], 999, false); - } - } -} diff --git a/tests/benchmarks/src/com/android/server/net/OWNERS b/tests/benchmarks/src/com/android/server/net/OWNERS deleted file mode 100644 index aa87958f1d53..000000000000 --- a/tests/benchmarks/src/com/android/server/net/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /services/core/java/com/android/server/net/OWNERS diff --git a/tests/componentalias/AndroidTest-template.xml b/tests/componentalias/AndroidTest-template.xml index 2d4621702329..afdfe79ea4a4 100644 --- a/tests/componentalias/AndroidTest-template.xml +++ b/tests/componentalias/AndroidTest-template.xml @@ -21,8 +21,6 @@ <option name="test-file-name" value="ComponentAliasTests2.apk" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> - <option name="run-command" value="am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android" /> - <!-- Exempt the helper APKs from the BG restriction, so they can start BG services. --> <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests" /> <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub1" /> diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java index 89db2f724302..9658d6f6a698 100644 --- a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java +++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java @@ -17,6 +17,7 @@ package android.content.componentalias.tests; import android.content.ComponentName; import android.content.Context; +import android.os.Build; import android.provider.DeviceConfig; import android.util.Log; @@ -27,6 +28,7 @@ import com.android.compatibility.common.util.ShellUtils; import com.android.compatibility.common.util.TestUtils; import org.junit.AfterClass; +import org.junit.Assume; import org.junit.Before; import java.util.function.Consumer; @@ -37,7 +39,11 @@ public class BaseComponentAliasTest { protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER); @Before - public void enableComponentAlias() throws Exception { + public void enableComponentAliasWithCompatFlag() throws Exception { + Assume.assumeTrue(Build.isDebuggable()); + ShellUtils.runShellCommand( + "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android"); + sDeviceConfig.set("enable_experimental_component_alias", ""); sDeviceConfig.set("component_alias_overrides", ""); // Make sure the feature is actually enabled. @@ -49,6 +55,8 @@ public class BaseComponentAliasTest { @AfterClass public static void restoreDeviceConfig() throws Exception { + ShellUtils.runShellCommand( + "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android"); sDeviceConfig.close(); } diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java new file mode 100644 index 000000000000..52c6d5b8ae12 --- /dev/null +++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java @@ -0,0 +1,63 @@ +/* + * 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 android.content.componentalias.tests; + +import android.os.Build; +import android.provider.DeviceConfig; + +import com.android.compatibility.common.util.DeviceConfigStateHelper; +import com.android.compatibility.common.util.ShellUtils; +import com.android.compatibility.common.util.TestUtils; + +import org.junit.AfterClass; +import org.junit.Assume; +import org.junit.Test; + +public class ComponentAliasEnableWithDeviceConfigTest { + protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER); + + @AfterClass + public static void restoreDeviceConfig() throws Exception { + sDeviceConfig.close(); + } + + @Test + public void enableComponentAliasWithCompatFlag() throws Exception { + Assume.assumeTrue(Build.isDebuggable()); + + sDeviceConfig.set("component_alias_overrides", ""); + + // First, disable with both compat-id and device config. + ShellUtils.runShellCommand( + "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android"); + sDeviceConfig.set("enable_experimental_component_alias", ""); + + TestUtils.waitUntil("Wait until component alias is actually enabled", () -> { + return ShellUtils.runShellCommand("dumpsys activity component-alias") + .indexOf("Enabled: false") > 0; + }); + + // Then, enable by device config. + sDeviceConfig.set("enable_experimental_component_alias", "true"); + + // Make sure the feature is actually enabled. + TestUtils.waitUntil("Wait until component alias is actually enabled", () -> { + return ShellUtils.runShellCommand("dumpsys activity component-alias") + .indexOf("Enabled: true") > 0; + }); + } +} diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java new file mode 100644 index 000000000000..7935476d6156 --- /dev/null +++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java @@ -0,0 +1,60 @@ +/* + * 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 android.content.componentalias.tests; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Build; +import android.provider.DeviceConfig; + +import com.android.compatibility.common.util.DeviceConfigStateHelper; +import com.android.compatibility.common.util.ShellUtils; + +import org.junit.AfterClass; +import org.junit.Assume; +import org.junit.Test; + +/** + * Test to make sure component-alias can't be enabled on user builds. + */ +public class ComponentAliasNotSupportedOnUserBuildTest { + protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER); + + @AfterClass + public static void restoreDeviceConfig() throws Exception { + sDeviceConfig.close(); + } + + @Test + public void enableComponentAliasWithCompatFlag() throws Exception { + Assume.assumeFalse(Build.isDebuggable()); + + // Try to enable it by both the device config and compat-id. + sDeviceConfig.set("enable_experimental_component_alias", "true"); + ShellUtils.runShellCommand( + "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android"); + + // Sleep for an arbitrary amount of time, so the config would sink in, if there was + // no "not on user builds" check. + + Thread.sleep(5000); + + // Make sure the feature is still disabled. + assertThat(ShellUtils.runShellCommand("dumpsys activity component-alias") + .indexOf("Enabled: false") > 0).isTrue(); + } +} |